From dafba9579e5695f2a490b08135173ba68b5f6ac2 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Thu, 29 Jun 2023 15:24:36 +0100 Subject: [PATCH 01/59] initial commit --- ...t_weaver-fabric-fabric-asset-transfer.yaml | 367 ++++++ ...est_weaver-fabric-fabric-data-sharing.yaml | 1044 ++++++++++++++++ weaver/common/protos-rs/Cargo.lock | 317 +++-- weaver/common/protos-rs/build.rs | 1 + weaver/common/protos-rs/pkg/Cargo.lock | 1059 +++++++++++++++++ .../pkg/src/generated/networks.networks.rs | 71 ++ .../pkg/src/generated/relay.asset_transfer.rs | 592 +++++++++ weaver/common/protos-rs/pkg/src/lib.rs | 3 + weaver/common/protos/networks/networks.proto | 4 + .../common/protos/relay/asset_transfer.proto | 94 ++ weaver/core/relay/Cargo.lock | 467 +++++--- weaver/core/relay/Cargo.toml | 10 +- weaver/core/relay/src/satp_client.rs | 59 + .../src/services/asset_transfer_service.rs | 127 ++ .../relay/src/services/network_service.rs | 245 ++++ 15 files changed, 4141 insertions(+), 319 deletions(-) create mode 100644 .github/workflows/test_weaver-fabric-fabric-asset-transfer.yaml create mode 100644 .github/workflows/test_weaver-fabric-fabric-data-sharing.yaml create mode 100644 weaver/common/protos-rs/pkg/Cargo.lock create mode 100644 weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs create mode 100644 weaver/common/protos/relay/asset_transfer.proto create mode 100644 weaver/core/relay/src/satp_client.rs create mode 100644 weaver/core/relay/src/services/asset_transfer_service.rs diff --git a/.github/workflows/test_weaver-fabric-fabric-asset-transfer.yaml b/.github/workflows/test_weaver-fabric-fabric-asset-transfer.yaml new file mode 100644 index 0000000000..8ca1a23b13 --- /dev/null +++ b/.github/workflows/test_weaver-fabric-fabric-asset-transfer.yaml @@ -0,0 +1,367 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + +# This is a basic workflow to help you get started with Actions + +name: Test Asset Transfer + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [ main ] + pull_request: + branches: [ main ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + fabric-fabric-asset-transfer-local: + # if: ${{ false }} + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3.5.2 + + - name: Install Yarn + run: npm install -g yarn + + - name: Install Envsubst + run: apt-get update && apt-get install gettext-base + + - name: Set up JDK 8 + uses: actions/setup-java@v3.11.0 + with: + java-version: '8' + distribution: 'adopt' + + - name: Set up Go + uses: actions/setup-go@v4.0.0 + with: + go-version: '1.20.2' + + - name: Use Node.js 16.x + uses: actions/setup-node@v3.6.0 + with: + node-version: 16.x + + - name: Install RUST Toolchain minimal stable with clippy and rustfmt + uses: actions-rs/toolchain@v1.0.6 + with: + profile: minimal + toolchain: stable + components: rustfmt, clippy + + - name: Get Latest Relay Dependencies + run: | + make protos-local + cargo update -p nom + cargo update -p lexical-core + working-directory: weaver/core/relay + + - name: Use Protoc 3.15 + run: | + curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip + unzip protoc-3.15.6-linux-x86_64.zip -d protoc + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + + # PROTOS + - name: Build GO Protos + run: | + export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" + make build + working-directory: weaver/common/protos-go + + # PROTOS + - name: Build JS Protos + run: | + export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" + make build + working-directory: weaver/common/protos-js + + - name: Build Java Protos + run: make build + working-directory: weaver/common/protos-java-kt + + # Build Dependencies + - name: Build Fabric Interop SDK + run: make build-local + working-directory: weaver/sdks/fabric/interoperation-node-sdk + + - name: Build Fabric CLI + run: make build-local + working-directory: weaver/samples/fabric/fabric-cli + + - name: Build Relay + run: make + working-directory: weaver/core/relay + + - name: Build Fabric Driver + run: make build-local + working-directory: weaver/core/drivers/fabric-driver + + - name: Build IIN Agent + run: make build-local + working-directory: weaver/core/identity-management/iin-agent + + # FABRIC NETWORK + + - name: Start Fabric Network + run: make start-interop-local CHAINCODE_NAME=simpleassettransfer + working-directory: weaver/tests/network-setups/fabric/dev + + # RELAY + - name: Start Relay for network1 + run: RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server &> relay-n1.out & + working-directory: weaver/core/relay + + - name: Start Relay for network2 + run: RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server &> relay-n2.out & + working-directory: weaver/core/relay + + # FABRIC DRIVER + - name: Setup Fabric Driver .env + run: | + cp .env.template .env + CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json + sed -i "s#path_to_connection_profile#${CCP_PATH}#g" .env + working-directory: weaver/core/drivers/fabric-driver + + - name: Start Fabric Driver for network1 + run: npm run dev &> fdriver-n1.out & + working-directory: weaver/core/drivers/fabric-driver + + - name: Start Fabric Driver for network2 + run: CONNECTION_PROFILE=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev &> fdriver-n2.out & + working-directory: weaver/core/drivers/fabric-driver + + # IIN AGENT + - name: Setup Fabric IIN Config + run: | + # FABRIC CONFIG + cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n1.json + CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json + sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n1.json + cat src/fabric-ledger/config-n1.json + cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n2.json + CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json + sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n2.json + cat src/fabric-ledger/config-n2.json + # DNS CONFIG + sed -i "s#iin-agent-Org1MSP-network1#localhost#g" docker-testnet/configs/dnsconfig.json + sed -i "s#iin-agent-Org1MSP-network2#localhost#g" docker-testnet/configs/dnsconfig.json + cat docker-testnet/configs/dnsconfig.json + working-directory: weaver/core/identity-management/iin-agent + + - name: Setup Fabric IIN Env + run: | + cp .env.template .env + sed -i "s##Org1MSP#g" .env + sed -i "s#^DLT_TYPE=.*#DLT_TYPE=fabric#g" .env + sed -i "s##interop#g" .env + sed -i "s#^DNS_CONFIG_PATH=#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig.json#g" .env + sed -i "s#^SECURITY_DOMAIN_CONFIG_PATH=#SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json#g" .env + sed -i "s#^CONFIG_PATH=#CONFIG_PATH=./src/fabric-ledger/config-n1.json#g" .env + sed -i "s#^AUTO_SYNC=#AUTO_SYNC=false#g" .env + cat .env + working-directory: weaver/core/identity-management/iin-agent + + - name: Start Fabric IIN Agent for network1 + run: npm run dev &> iinagent-n1.out & + working-directory: weaver/core/identity-management/iin-agent + + - name: Start Fabric IIN Agent for network2 + run: IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2.json npm run dev &> iinagent-n2.out & + working-directory: weaver/core/identity-management/iin-agent + + # FABRIC CLI + - name: Setup Fabric CLI ENV + run: | + echo ${GITHUB_WORKSPACE} + cp .env.template .env + ./bin/fabric-cli env set-file ./.env + ./bin/fabric-cli env set MEMBER_CREDENTIAL_FOLDER ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/src/data/credentials + ./bin/fabric-cli env set CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/config.json + ./bin/fabric-cli env set DEFAULT_APPLICATION_CHAINCODE simpleassettransfer + ./bin/fabric-cli env set REMOTE_CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/remote-network-config.json + ./bin/fabric-cli env set CHAINCODE_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/chaincode.json + cat .env + working-directory: weaver/samples/fabric/fabric-cli + + - name: Setup Fabric CLI Config + run: | + echo ${GITHUB_WORKSPACE} + cp config.template.json config.json + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" config.json + ###### Change line number in following commands if config is modified ##### + ./bin/fabric-cli config set network2 aclPolicyPrincipalType ca + ./bin/fabric-cli config set network1 chaincode simpleassettransfer + ./bin/fabric-cli config set network2 chaincode simpleassettransfer + cp chaincode.json.template chaincode.json + cp remote-network-config.json.template remote-network-config.json + working-directory: weaver/samples/fabric/fabric-cli + + + - name: Fabric CLI Init + run: | + ./bin/fabric-cli configure create all --local-network=network1 + ./bin/fabric-cli configure create all --local-network=network2 + ./bin/fabric-cli configure network --local-network=network1 + ./bin/fabric-cli configure network --local-network=network2 + ./scripts/initAssetsForTransfer.sh + working-directory: weaver/samples/fabric/fabric-cli + + - name: Fabric Sync Membership using IIN Agent + run: | + ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 + sleep 10 + tail -10 ../../../core/identity-management/iin-agent/iinagent-n1.out + ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 + sleep 10 + tail -10 ../../../core/identity-management/iin-agent/iinagent-n2.out + working-directory: weaver/samples/fabric/fabric-cli + + # FABRIC CLI + - name: Asset Transfer Fabric CLI Non-Fungible Tests + run: | + COUNT=0 + TOTAL=8 + + # FABRIC2 - FABRIC1 + ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=bond --ref=a03 --data-file=src/data/assetsForTransfer.json &> tmp.out + tail -n 1 tmp.out | grep "Asset pledged with ID" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') + + # FABRIC1 - FABRIC2 + ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a03 &> tmp.out + tail -n 1 tmp.out | grep "Called Function ClaimRemoteAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network1 &> tmp.out + tail -n 2 tmp.out | grep "Error: the asset a03 does not exist" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network2 &> tmp.out + #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=20 --type=bond --ref=a04 --data-file=src/data/assetsForTransfer.json &> tmp.out + cat tmp.out + + CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') + sleep 20 + + ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a04 &> tmp.out + tail -n 1 tmp.out | grep "cannot claim asset with pledgeId $CID as the expiry time has elapsed" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a04 &> tmp.out + tail -n 1 tmp.out | grep "Called Function ReclaimAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network1 &> tmp.out + #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network2 &> tmp.out + tail -n 2 tmp.out | grep "Error: the asset a04 does not exist" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # RESULT + echo "Passed $COUNT/$TOTAL Tests." + + if [ $COUNT == $TOTAL ]; then + exit 0 + else + exit 1 + fi + working-directory: weaver/samples/fabric/fabric-cli + + # FABRIC CLI + - name: Asset Transfer Fabric CLI Fungible Tests + run: | + COUNT=0 + TOTAL=8 + + # FABRIC2 - FABRIC1 + ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=token --units=50 --owner=alice --data-file=src/data/tokensForTransfer.json &> tmp.out + tail -n 1 tmp.out | grep "Asset pledged with ID" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') + + # FABRIC1 - FABRIC2 + ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token.fabric --pledge-id=$CID --param=token1:50 &> tmp.out + tail -n 1 tmp.out | grep "Called Function ClaimRemoteTokenAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer GetMyWallet '[]' --local-network=network1 &> tmp.out + tail -n 2 tmp.out | grep "Result from network query: token1=\"9950\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer GetMyWallet '[]' --local-network=network2 &> tmp.out + tail -n 2 tmp.out | grep "Result from network query: token1=\"50\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=20 --type=token --units=100 --owner=alice --data-file=src/data/tokensForTransfer.json &> tmp.out + cat tmp.out + + CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') + sleep 20 + + ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token.fabric --pledge-id=$CID --param=token1:100 &> tmp.out + tail -n 1 tmp.out | grep "cannot claim asset with pledgeId $CID as the expiry time has elapsed" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=token.fabric --pledge-id=$CID --param=token1:100 &> tmp.out + tail -n 1 tmp.out | grep "Called Function ReclaimTokenAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer GetMyWallet '[]' --local-network=network1 &> tmp.out + tail -n 2 tmp.out | grep "Result from network query: token1=\"9950\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer GetMyWallet '[]' --local-network=network2 &> tmp.out + tail -n 2 tmp.out | grep "Result from network query: token1=\"50\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # RESULT + echo "Passed $COUNT/$TOTAL Tests." + + if [ $COUNT == $TOTAL ]; then + exit 0 + else + exit 1 + fi + working-directory: weaver/samples/fabric/fabric-cli + + - name: DEBUG Logs - fabric n1 relay + if: failure() + run: cat weaver/core/relay/relay-n1.out + + - name: DEBUG Logs - fabric n2 relay + if: failure() + run: cat weaver/core/relay/relay-n2.out + + - name: DEBUG Logs - fabric n1 driver + if: failure() + run: cat weaver/core/drivers/fabric-driver/fdriver-n1.out + + - name: DEBUG Logs - fabric n2 driver + if: failure() + run: cat weaver/core/drivers/fabric-driver/fdriver-n2.out diff --git a/.github/workflows/test_weaver-fabric-fabric-data-sharing.yaml b/.github/workflows/test_weaver-fabric-fabric-data-sharing.yaml new file mode 100644 index 0000000000..fa84bac89f --- /dev/null +++ b/.github/workflows/test_weaver-fabric-fabric-data-sharing.yaml @@ -0,0 +1,1044 @@ +# Copyright IBM Corp. All Rights Reserved. +# +# SPDX-License-Identifier: CC-BY-4.0 + +# This is a basic workflow to help you get started with Actions + +name: Test Data Sharing + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [ main ] + pull_request: + branches: [ main ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + fabric-fabric-data-sharing: + if: ${{ false }} + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3.5.2 + + - name: Set up JDK 8 + uses: actions/setup-java@v3.11.0 + with: + java-version: '8' + distribution: 'adopt' + + - name: Set up Go + uses: actions/setup-go@v4.0.0 + with: + go-version: '1.20.2' + + - name: Use Node.js 14.x + uses: actions/setup-node@v3.6.0 + with: + node-version: 14.x + + # CORDA NETWORK + - name: Generate github.properties + run: | + echo "Using ${GITHUB_ACTOR} user." + echo "username=${GITHUB_ACTOR}" >> github.properties + echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.properties + echo "url=https://maven.pkg.github.com/${GITHUB_ACTOR}/cacti" >> github.properties + + echo "Using ${GITHUB_ACTOR} user." + echo "username=${GITHUB_ACTOR}" >> github.main.properties + echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.main.properties + echo "url=https://maven.pkg.github.com/hyperledger/cacti" >> github.main.properties + + ./scripts/get-cordapps.sh || mv github.main.properties github.properties + + cat github.properties + working-directory: weaver/tests/network-setups/corda + + - name: Start Corda Network + run: | + sed -i "/docker logs corda_partya_1 -f/"' s/^/#/' "scripts/start-nodes.sh" + make start &> corda-net.out & + working-directory: weaver/tests/network-setups/corda + + # FABRIC NETWORK + - name: Start Fabric Network + run: make start-interop PROFILE='2-nodes' + working-directory: weaver/tests/network-setups/fabric/dev + + - name: Corda Network logs + run: | + cat tests/network-setups/corda/corda-net.out + docker logs corda_partya_1 + working-directory: weaver + + # RELAY + - name: Edit Relay docker compose + run: make convert-compose-method2 + working-directory: weaver/core/relay + + - name: Start Relay for network1 + run: make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1' + working-directory: weaver/core/relay + + - name: Start Relay for network2 + run: make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2' + working-directory: weaver/core/relay + + - name: Start Relay for Corda_Network + run: make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda' + working-directory: weaver/core/relay + + - name: Start Relay for Corda_Network2 + run: make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2' + working-directory: weaver/core/relay + + # FABRIC DRIVER + - name: Setup Fabric Driver .env + run: | + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet-envs/.env.n1 + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet-envs/.env.n2 + working-directory: weaver/core/drivers/fabric-driver + + - name: Start Fabric Driver for network1 + run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2) + working-directory: weaver/core/drivers/fabric-driver + + - name: Start Fabric Driver for network2 + run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2) + working-directory: weaver/core/drivers/fabric-driver + + # IIN AGENT + - name: Setup Fabric IIN Env + run: | + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n1.org1 + sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n1.org1 + sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n1.org1 + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n1.org2 + sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n1.org2 + sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n1.org2 + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n2.org1 + sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n2.org1 + sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n2.org1 + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n2.org2 + sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n2.org2 + sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n2.org2 + working-directory: weaver/core/identity-management/iin-agent + + - name: Start Fabric IIN Agent for network1 + run: | + make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2) + make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2) + working-directory: weaver/core/identity-management/iin-agent + + - name: Start Fabric IIN Agent for network2 + run: | + make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2) + make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2) + working-directory: weaver/core/identity-management/iin-agent + + # CORDA DRIVER + - name: Start Corda Driver + run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda' + working-directory: weaver/core/drivers/corda-driver + + - name: Start Corda_Network2 Driver + run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2' + working-directory: weaver/core/drivers/corda-driver + + # FABRIC CLI + - name: Setup Fabric CLI .npmrc + run: | + cp .npmrc.template .npmrc + sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc + cat .npmrc + working-directory: weaver/samples/fabric/fabric-cli + - name: Build Fabric CLI + run: | + npm install --global yarn + make build + working-directory: weaver/samples/fabric/fabric-cli + - name: Setup Fabric CLI Config + run: | + echo ${GITHUB_WORKSPACE} + cp config.template.json config.json + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" config.json + working-directory: weaver/samples/fabric/fabric-cli + - name: Setup Fabric CLI ENV + run: | + echo ${GITHUB_WORKSPACE} + cp .env.template .env + sed -i "s/CHAINCODE_PATH=.*/CHAINCODE_PATH=\.\/chaincode\.json/g" .env + ./bin/fabric-cli env set MEMBER_CREDENTIAL_FOLDER ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/src/data/credentials_docker + ./bin/fabric-cli env set CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/config.json + cat .env + working-directory: weaver/samples/fabric/fabric-cli + + - name: Fabric CLI Configure ALL + run: ./bin/fabric-cli configure all network1 network2 --num-orgs=2 + working-directory: weaver/samples/fabric/fabric-cli + + - name: Fabric Sync Membership using IIN Agent + run: | + ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 + sleep 30 + docker logs iin-agent-Org1MSP-network1 + docker logs iin-agent-Org1MSP-network2 + ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 + sleep 30 + docker logs iin-agent-Org1MSP-network1 + docker logs iin-agent-Org1MSP-network2 + working-directory: weaver/samples/fabric/fabric-cli + + # CORDA CLIENT + - name: Corda CLI Initialize Vault + run: make initialise-vault-docker + working-directory: weaver/samples/corda/corda-simple-application + + - name: Data Transfer Corda Client Tests + run: | + COUNT=0 + TOTAL=8 + + # CORDA-CORDA2 + ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-corda2:9082/Corda_Network2/corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H 1> tmp.out + cat tmp.out | grep "SimpleState(key=H, value=\[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./clients/build/install/clients/bin/clients get-state H 1> tmp.out + cat tmp.out | grep "SimpleState(key=H, value=\[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # CORDA2-CORDA + + NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C 1> tmp.out + cat tmp.out | grep "SimpleState(key=C, value=\[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state C 1> tmp.out + cat tmp.out | grep "SimpleState(key=C, value=\[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # CORDA - FABRIC1 + ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network1:9080/network1/mychannel:simplestate:Read:a 1> tmp.out + cat tmp.out | grep "SimpleState(key=a, value=Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./clients/build/install/clients/bin/clients get-state a 1> tmp.out + cat tmp.out | grep "SimpleState(key=a, value=Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # CORDA - FABRIC2 + ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus 1> tmp.out + cat tmp.out | grep "SimpleState(key=Arcturus, value=17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./clients/build/install/clients/bin/clients get-state Arcturus 1> tmp.out + cat tmp.out | grep "SimpleState(key=Arcturus, value=17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # RESULT + echo "Passed $COUNT/$TOTAL Tests." + + if [ $COUNT == $TOTAL ]; then + exit 0 + else + exit 1 + fi + working-directory: weaver/samples/corda/corda-simple-application + + # FABRIC CLI + - name: Data Transfer Fabric CLI Tests + run: | + COUNT=0 + TOTAL=12 + + # FABRIC2 - FABRIC1 + cp chaincode.json.template chaincode.json + ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP relay-network1:9080/network1/mychannel:simplestate:Read:a &> tmp.out + tail -n 1 tmp.out | grep "Args: a, Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["a"]' --local-network=network2 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC1 - FABRIC2 + sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"Arcturus\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus &> tmp.out + tail -n 1 tmp.out | grep "Args: Arcturus, 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC2 - FABRIC1 - CONFIDENTIAL + sed -i "s/\"args\"\: \[\"Arcturus\"/\"args\"\: \[\"b\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --e2e-confidentiality=true relay-network1:9080/network1/mychannel:simplestate:Read:b &> tmp.out + tail -n 1 tmp.out | grep "Args: b, Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["b"]' --local-network=network2 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC1 - FABRIC2 - CONFIDENTIAL + sed -i "s/\"args\"\: \[\"b\"/\"args\"\: \[\"Betelgeuse\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --e2e-confidentiality=true relay-network2:9083/network2/mychannel:simplestate:Read:Betelgeuse &> tmp.out + tail -n 1 tmp.out | grep "Args: Betelgeuse, 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["Betelgeuse"]' --local-network=network1 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["Arcturus"]' --local-network=network1 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC1 - CORDA + cp chaincode.json.template chaincode.json + sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"H\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true &> tmp.out + tail -n 1 tmp.out | grep "Args: H, \[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["H"]' --local-network=network1 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: \[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC2 - CORDA + cp chaincode.json.template chaincode.json + sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"C\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C --debug=true &> tmp.out + tail -n 1 tmp.out | grep "Args: C, \[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["C"]' --local-network=network2 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: \[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + + # RESULT + echo "Passed $COUNT/$TOTAL Tests." + + if [ $COUNT == $TOTAL ]; then + exit 0 + else + exit 1 + fi + working-directory: weaver/samples/fabric/fabric-cli + + - name: DEBUG Logs - corda partya + if: failure() + run: docker logs corda_partya_1 + + - name: DEBUG Logs - corda network2 partya + if: failure() + run: docker logs corda_network2_partya_1 + + - name: DEBUG Logs - fabric n1 relay + if: failure() + run: docker logs relay-network1 + + - name: DEBUG Logs - fabric n2 relay + if: failure() + run: docker logs relay-network2 + + - name: DEBUG Logs - corda relay + if: failure() + run: docker logs relay-corda + + - name: DEBUG Logs - corda2 relay + if: failure() + run: docker logs relay-corda2 + + - name: DEBUG Logs - fabric n1 driver + if: failure() + run: docker logs driver-fabric-network1 + + - name: DEBUG Logs - fabric n2 driver + if: failure() + run: docker logs driver-fabric-network2 + + - name: DEBUG Logs - corda driver + if: failure() + run: docker logs driver-corda-Corda_Network + + - name: DEBUG Logs - corda2 driver + if: failure() + run: docker logs driver-corda-Corda_Network2 + + fabric-fabric-data-sharing-docker-local: + # if: ${{ false }} + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3.5.2 + + - name: Install Yarn + run: npm install -g yarn + + - name: Install Envsubst + run: apt-get update && apt-get install gettext-base + + - name: Set up JDK 8 + uses: actions/setup-java@v3.11.0 + with: + java-version: '8' + distribution: 'adopt' + + - name: Set up Go + uses: actions/setup-go@v4.0.0 + with: + go-version: '1.20.2' + + - name: Use Node.js 14.x + uses: actions/setup-node@v3.6.0 + with: + node-version: 14.x + + - name: Use Protoc 3.15 + run: | + curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip + unzip protoc-3.15.6-linux-x86_64.zip -d protoc + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + + # PROTOS + - name: Build GO Protos + run: | + export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" + make build + working-directory: weaver/common/protos-go + + # PROTOS + - name: Build JS Protos + run: | + export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" + make build + working-directory: weaver/common/protos-js + + - name: Build Java Protos + run: make build + working-directory: weaver/common/protos-java-kt + + # Build Dependencies + - name: Build Fabric Interop SDK + run: make build-local + working-directory: weaver/sdks/fabric/interoperation-node-sdk + + - name: Build Fabric CLI + run: make build-local + working-directory: weaver/samples/fabric/fabric-cli + + - name: Build Relay + run: make build-server-local + working-directory: weaver/core/relay + + - name: Build Fabric Driver + run: make build-image-local + working-directory: weaver/core/drivers/fabric-driver + + - name: Build IIN Agent + run: make build-image-local + working-directory: weaver/core/identity-management/iin-agent + + # FABRIC NETWORK + - name: Start Fabric Network + run: make start-interop-local PROFILE='2-nodes' + working-directory: weaver/tests/network-setups/fabric/dev + + # RELAY + - name: Edit Relay docker compose + run: make convert-compose-method2 + working-directory: weaver/core/relay + + - name: Start Relay for network1 + run: | + sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-relay-server#g" docker/testnet-envs/.env.n1 + make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1' + working-directory: weaver/core/relay + + - name: Start Relay for network2 + run: | + sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-relay-server#g" docker/testnet-envs/.env.n2 + make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2' + working-directory: weaver/core/relay + + # FABRIC DRIVER + - name: Setup Fabric Driver .env + run: | + sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-driver-fabric#g" docker-testnet-envs/.env.n1 + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet-envs/.env.n1 + sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-driver-fabric#g" docker-testnet-envs/.env.n2 + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet-envs/.env.n2 + working-directory: weaver/core/drivers/fabric-driver + + - name: Start Fabric Driver for network1 + run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2) + working-directory: weaver/core/drivers/fabric-driver + + - name: Start Fabric Driver for network2 + run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2) + working-directory: weaver/core/drivers/fabric-driver + + # IIN AGENT + - name: Setup Fabric IIN Env + run: | + sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-iin-agent#g" docker-testnet/envs/.env.n1.org1 + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n1.org1 + sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n1.org1 + sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n1.org1 + sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-iin-agent#g" docker-testnet/envs/.env.n1.org2 + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n1.org2 + sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n1.org2 + sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n1.org2 + sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-iin-agent#g" docker-testnet/envs/.env.n2.org1 + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n2.org1 + sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n2.org1 + sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n2.org1 + sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-iin-agent#g" docker-testnet/envs/.env.n2.org2 + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n2.org2 + sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n2.org2 + sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n2.org2 + working-directory: weaver/core/identity-management/iin-agent + + - name: Start Fabric IIN Agent for network1 + run: | + make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2) + make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2) + working-directory: weaver/core/identity-management/iin-agent + + - name: Start Fabric IIN Agent for network2 + run: | + make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2) + make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2) + working-directory: weaver/core/identity-management/iin-agent + + # FABRIC CLI + - name: Setup Fabric CLI Config + run: | + echo ${GITHUB_WORKSPACE} + cp config.template.json config.json + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" config.json + working-directory: weaver/samples/fabric/fabric-cli + - name: Setup Fabric CLI ENV + run: | + echo ${GITHUB_WORKSPACE} + cp .env.template .env + sed -i "s/CHAINCODE_PATH=.*/CHAINCODE_PATH=\.\/chaincode\.json/g" .env + ./bin/fabric-cli env set MEMBER_CREDENTIAL_FOLDER ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/src/data/credentials_docker + ./bin/fabric-cli env set CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/config.json + cat .env + working-directory: weaver/samples/fabric/fabric-cli + + - name: Fabric CLI Configure ALL + run: ./bin/fabric-cli configure all network1 network2 --num-orgs=2 + working-directory: weaver/samples/fabric/fabric-cli + + - name: Fabric Sync Membership using IIN Agent + run: | + ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 + sleep 30 + docker logs iin-agent-Org1MSP-network1 + docker logs iin-agent-Org1MSP-network2 + ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 + sleep 30 + docker logs iin-agent-Org1MSP-network1 + docker logs iin-agent-Org1MSP-network2 + working-directory: weaver/samples/fabric/fabric-cli + + # FABRIC CLI + - name: Data Transfer Fabric CLI Tests + run: | + COUNT=0 + TOTAL=8 + + # FABRIC2 - FABRIC1 + cp chaincode.json.template chaincode.json + ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP relay-network1:9080/network1/mychannel:simplestate:Read:a &> tmp.out + tail -n 1 tmp.out | grep "Args: a, Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["a"]' --local-network=network2 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC1 - FABRIC2 + sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"Arcturus\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus &> tmp.out + tail -n 1 tmp.out | grep "Args: Arcturus, 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["Arcturus"]' --local-network=network1 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC2 - FABRIC1 - CONFIDENTIAL + sed -i "s/\"args\"\: \[\"Arcturus\"/\"args\"\: \[\"b\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --e2e-confidentiality=true relay-network1:9080/network1/mychannel:simplestate:Read:b &> tmp.out + tail -n 1 tmp.out | grep "Args: b, Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["b"]' --local-network=network2 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC1 - FABRIC2 - CONFIDENTIAL + sed -i "s/\"args\"\: \[\"b\"/\"args\"\: \[\"Betelgeuse\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --e2e-confidentiality=true relay-network2:9083/network2/mychannel:simplestate:Read:Betelgeuse &> tmp.out + tail -n 1 tmp.out | grep "Args: Betelgeuse, 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["Betelgeuse"]' --local-network=network1 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # RESULT + echo "Passed $COUNT/$TOTAL Tests." + + if [ $COUNT == $TOTAL ]; then + exit 0 + else + exit 1 + fi + working-directory: weaver/samples/fabric/fabric-cli + + - name: DEBUG Logs - fabric n1 relay + if: failure() + run: docker logs relay-network1 + + - name: DEBUG Logs - fabric n2 relay + if: failure() + run: docker logs relay-network2 + + - name: DEBUG Logs - fabric n1 driver + if: failure() + run: docker logs driver-fabric-network1 + + - name: DEBUG Logs - fabric n2 driver + if: failure() + run: docker logs driver-fabric-network2 + + fabric-fabric-data-sharing-local: + # if: ${{ false }} + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3.5.2 + + - name: Set up JDK 8 + uses: actions/setup-java@v3.11.0 + with: + java-version: '8' + distribution: 'adopt' + + - name: Set up Go + uses: actions/setup-go@v4.0.0 + with: + go-version: '1.20.2' + + - name: Use Node.js 16.x + uses: actions/setup-node@v3.6.0 + with: + node-version: 16.x + + - name: Install RUST Toolchain minimal stable with clippy and rustfmt + uses: actions-rs/toolchain@v1.0.6 + with: + profile: minimal + toolchain: stable + components: rustfmt, clippy + + - name: Get Latest Relay Dependencies + run: | + make protos-local + cargo update -p nom + cargo update -p lexical-core + working-directory: weaver/core/relay + + - name: Use Protoc 3.15 + run: | + curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip + unzip protoc-3.15.6-linux-x86_64.zip -d protoc + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + + # PROTOS + - name: Build GO Protos + run: | + export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" + make build + working-directory: weaver/common/protos-go + + # PROTOS + - name: Build JS Protos + run: | + export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" + make build + working-directory: weaver/common/protos-js + + - name: Build Java Protos + run: make build + working-directory: weaver/common/protos-java-kt + + # Build Dependencies + - name: Build Corda Interop App + run: make build-local + working-directory: weaver/core/network/corda-interop-app + + - name: Build Corda Interop SDK + run: make build + working-directory: weaver/sdks/corda + + - name: Build Corda SimpleApplication + run: make build-local + working-directory: weaver/samples/corda/corda-simple-application + + - name: Build Fabric Interop SDK + run: make build-local + working-directory: weaver/sdks/fabric/interoperation-node-sdk + + - name: Build Fabric CLI + run: make build-local + working-directory: weaver/samples/fabric/fabric-cli + + - name: Build Relay + run: make + working-directory: weaver/core/relay + + - name: Build Fabric Driver + run: make build-local + working-directory: weaver/core/drivers/fabric-driver + + - name: Build Corda Driver + run: make build-local + working-directory: weaver/core/drivers/corda-driver + + - name: Build IIN Agent + run: make build-local + working-directory: weaver/core/identity-management/iin-agent + + # CORDA NETWORK + - name: Start Corda Network + run: | + sed -i "/docker logs corda_partya_1 -f/"' s/^/#/' "scripts/start-nodes.sh" + make start-local &> corda-net.out & + working-directory: weaver/tests/network-setups/corda + + # FABRIC NETWORK + + - name: Start Fabric Network + run: make start-interop-local + working-directory: weaver/tests/network-setups/fabric/dev + + - name: Corda Network logs + run: | + cat tests/network-setups/corda/corda-net.out + docker logs corda_partya_1 + working-directory: weaver + + # RELAY + - name: Start Relay for network1 + run: RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server &> relay-n1.out & + working-directory: weaver/core/relay + + - name: Start Relay for network2 + run: RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server &> relay-n2.out & + working-directory: weaver/core/relay + + - name: Start Relay for Corda_Network + run: RELAY_CONFIG=config/Corda_Relay.toml cargo run --bin server &> relay-corda.out & + working-directory: weaver/core/relay + + - name: Start Relay for Corda_Network2 + run: RELAY_CONFIG=config/Corda_Relay2.toml cargo run --bin server &> relay-corda2.out & + working-directory: weaver/core/relay + + # FABRIC DRIVER + - name: Setup Fabric Driver .env + run: | + cp .env.template .env + CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json + sed -i "s#path_to_connection_profile#${CCP_PATH}#g" .env + working-directory: weaver/core/drivers/fabric-driver + + - name: Start Fabric Driver for network1 + run: npm run dev &> fdriver-n1.out & + working-directory: weaver/core/drivers/fabric-driver + + - name: Start Fabric Driver for network2 + run: CONNECTION_PROFILE=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev &> fdriver-n2.out & + working-directory: weaver/core/drivers/fabric-driver + + # IIN AGENT + - name: Setup Fabric IIN Config + run: | + # FABRIC CONFIG + cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n1.json + CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json + sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n1.json + cat src/fabric-ledger/config-n1.json + cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n2.json + CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json + sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n2.json + cat src/fabric-ledger/config-n2.json + # DNS CONFIG + sed -i "s#iin-agent-Org1MSP-network1#localhost#g" docker-testnet/configs/dnsconfig.json + sed -i "s#iin-agent-Org1MSP-network2#localhost#g" docker-testnet/configs/dnsconfig.json + cat docker-testnet/configs/dnsconfig.json + working-directory: weaver/core/identity-management/iin-agent + + - name: Setup Fabric IIN Env + run: | + cp .env.template .env + sed -i "s##Org1MSP#g" .env + sed -i "s#^DLT_TYPE=.*#DLT_TYPE=fabric#g" .env + sed -i "s##interop#g" .env + sed -i "s#^DNS_CONFIG_PATH=#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig.json#g" .env + sed -i "s#^SECURITY_DOMAIN_CONFIG_PATH=#SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json#g" .env + sed -i "s#^CONFIG_PATH=#CONFIG_PATH=./src/fabric-ledger/config-n1.json#g" .env + sed -i "s#^AUTO_SYNC=#AUTO_SYNC=false#g" .env + cat .env + working-directory: weaver/core/identity-management/iin-agent + + - name: Start Fabric IIN Agent for network1 + run: npm run dev &> iinagent-n1.out & + working-directory: weaver/core/identity-management/iin-agent + + - name: Start Fabric IIN Agent for network2 + run: IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2.json npm run dev &> iinagent-n2.out & + working-directory: weaver/core/identity-management/iin-agent + + # CORDA DRIVER + - name: Start Corda_Network Driver + run: ./build/install/driver-corda/bin/driver-corda &> corda-driver.out & + working-directory: weaver/core/drivers/corda-driver + + - name: Start Corda_Network2 Driver + run: DRIVER_PORT=9098 ./build/install/driver-corda/bin/driver-corda &> corda2-driver.out & + working-directory: weaver/core/drivers/corda-driver + + # FABRIC CLI + - name: Setup Fabric CLI Config + run: | + echo ${GITHUB_WORKSPACE} + cp config.template.json config.json + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" config.json + working-directory: weaver/samples/fabric/fabric-cli + - name: Setup Fabric CLI ENV + run: | + echo ${GITHUB_WORKSPACE} + cp .env.template .env + sed -i "s/CHAINCODE_PATH=.*/CHAINCODE_PATH=\.\/chaincode\.json/g" .env + ./bin/fabric-cli env set MEMBER_CREDENTIAL_FOLDER ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/src/data/credentials + ./bin/fabric-cli env set CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/config.json + cat .env + cp chaincode.json.template chaincode.json + working-directory: weaver/samples/fabric/fabric-cli + + - name: Fabric CLI Configure ALL + run: ./bin/fabric-cli configure all network1 network2 + working-directory: weaver/samples/fabric/fabric-cli + + - name: Fabric Sync Membership using IIN Agent + run: | + ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 + sleep 10 + tail -10 ../../../core/identity-management/iin-agent/iinagent-n1.out + ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 + sleep 10 + tail -10 ../../../core/identity-management/iin-agent/iinagent-n2.out + working-directory: weaver/samples/fabric/fabric-cli + + # CORDA CLIENT + - name: Corda CLI Initialize Vault + run: make initialise-vault + working-directory: weaver/samples/corda/corda-simple-application + + - name: Data Transfer Corda Client Tests + run: | + COUNT=0 + TOTAL=8 + + # CORDA-CORDA2 + ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9082/Corda_Network2/localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:H 1> tmp.out + cat tmp.out | grep "SimpleState(key=H, value=\[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./clients/build/install/clients/bin/clients get-state H 1> tmp.out + cat tmp.out | grep "SimpleState(key=H, value=\[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # CORDA2-CORDA + + NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C 1> tmp.out + cat tmp.out | grep "SimpleState(key=C, value=\[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state C 1> tmp.out + cat tmp.out | grep "SimpleState(key=C, value=\[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # CORDA - FABRIC1 + ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9080/network1/mychannel:simplestate:Read:a 1> tmp.out + cat tmp.out | grep "SimpleState(key=a, value=Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./clients/build/install/clients/bin/clients get-state a 1> tmp.out + cat tmp.out | grep "SimpleState(key=a, value=Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # CORDA - FABRIC2 + ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9083/network2/mychannel:simplestate:Read:Arcturus 1> tmp.out + cat tmp.out | grep "SimpleState(key=Arcturus, value=17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./clients/build/install/clients/bin/clients get-state Arcturus 1> tmp.out + cat tmp.out | grep "SimpleState(key=Arcturus, value=17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # RESULT + echo "Passed $COUNT/$TOTAL Tests." + + if [ $COUNT == $TOTAL ]; then + exit 0 + else + exit 1 + fi + working-directory: weaver/samples/corda/corda-simple-application + + # FABRIC CLI + - name: Data Transfer Fabric CLI Tests + run: | + COUNT=0 + TOTAL=12 + + # FABRIC2 - FABRIC1 + cp chaincode.json.template chaincode.json + ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP localhost:9080/network1/mychannel:simplestate:Read:a &> tmp.out + tail -n 1 tmp.out | grep "Args: a, Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["a"]' --local-network=network2 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC2 - FABRIC1 - CONFIDENTIAL + sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"b\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9080/network1/mychannel:simplestate:Read:b &> tmp.out + tail -n 1 tmp.out | grep "Args: b, Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["b"]' --local-network=network2 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC1 - FABRIC2 + sed -i "s/\"args\"\: \[\"b\"/\"args\"\: \[\"Arcturus\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP localhost:9083/network2/mychannel:simplestate:Read:Arcturus &> tmp.out + tail -n 1 tmp.out | grep "Args: Arcturus, 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["Arcturus"]' --local-network=network1 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC1 - FABRIC2 - CONFIDENTIAL + sed -i "s/\"args\"\: \[\"Arcturus\"/\"args\"\: \[\"Betelgeuse\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9083/network2/mychannel:simplestate:Read:Betelgeuse &> tmp.out + tail -n 1 tmp.out | grep "Args: Betelgeuse, 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["Betelgeuse"]' --local-network=network1 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC1 - CORDA + cp chaincode.json.template chaincode.json + sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"H\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true &> tmp.out + tail -n 1 tmp.out | grep "Args: H, \[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["H"]' --local-network=network1 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: \[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + # FABRIC2 - CORDA + cp chaincode.json.template chaincode.json + sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"C\"/g" chaincode.json + ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C --debug=true --debug=true &> tmp.out + tail -n 1 tmp.out | grep "Args: C, \[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + ./bin/fabric-cli chaincode query mychannel simplestate read '["C"]' --local-network=network2 &> tmp.out + tail -n 1 tmp.out | grep "Result from network query: \[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out + + + # RESULT + echo "Passed $COUNT/$TOTAL Tests." + + if [ $COUNT == $TOTAL ]; then + exit 0 + else + exit 1 + fi + working-directory: weaver/samples/fabric/fabric-cli + + - name: DEBUG Logs - corda partya + if: failure() + run: docker logs corda_partya_1 + + - name: DEBUG Logs - corda network2 partya + if: failure() + run: docker logs corda_network2_partya_1 + + - name: DEBUG Logs - fabric n1 relay + if: failure() + run: cat weaver/core/relay/relay-n1.out + + - name: DEBUG Logs - fabric n2 relay + if: failure() + run: cat weaver/core/relay/relay-n2.out + + - name: DEBUG Logs - corda relay + if: failure() + run: cat weaver/core/relay/relay-corda.out + + - name: DEBUG Logs - corda2 relay + if: failure() + run: cat weaver/core/relay/relay-corda2.out + + - name: DEBUG Logs - fabric n1 driver + if: failure() + run: cat weaver/core/drivers/fabric-driver/fdriver-n1.out + + - name: DEBUG Logs - fabric n2 driver + if: failure() + run: cat weaver/core/drivers/fabric-driver/fdriver-n2.out + + - name: DEBUG Logs - corda driver + if: failure() + run: cat weaver/core/drivers/corda-driver/corda-driver.out + + - name: DEBUG Logs - corda2 driver + if: failure() + run: cat weaver/core/drivers/corda-driver/corda2-driver.out diff --git a/weaver/common/protos-rs/Cargo.lock b/weaver/common/protos-rs/Cargo.lock index 74d6a70124..2570695f2d 100644 --- a/weaver/common/protos-rs/Cargo.lock +++ b/weaver/common/protos-rs/Cargo.lock @@ -2,17 +2,32 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" [[package]] name = "async-stream" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad445822218ce64be7a341abfb0b1ea43b5c23aa83902542a4542e78309d8e5e" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", @@ -21,13 +36,13 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] @@ -38,7 +53,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.22", ] [[package]] @@ -49,9 +64,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.12" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f8ccfd9221ee7d1f3d4b33e1f8319b3a81ed8f61f2ea40b37b859794b4491" +checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", @@ -77,9 +92,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2f958c80c248b34b9a877a643811be8dbca03ca5ba827f2b63baf3a81e5fc4e" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" dependencies = [ "async-trait", "bytes", @@ -92,6 +107,21 @@ dependencies = [ "tower-service", ] +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -100,9 +130,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "bitflags" @@ -123,9 +153,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytes" @@ -153,9 +183,9 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "errno" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", @@ -234,20 +264,26 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "h2" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -316,9 +352,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.25" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -371,9 +407,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi", "libc", @@ -397,9 +433,9 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -412,24 +448,21 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "linux-raw-sys" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "matchit" @@ -449,14 +482,22 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi", "windows-sys", ] @@ -467,17 +508,26 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +[[package]] +name = "object" +version = "0.30.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "petgraph" @@ -491,22 +541,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] @@ -539,18 +589,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.55" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0dd4be24fcdcfeaa12a432d588dc59bbad6cad3510c67e74a2b6b2fc950564" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", "prost-derive", @@ -558,9 +608,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" dependencies = [ "bytes", "heck", @@ -580,9 +630,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools", @@ -593,18 +643,18 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ "prost", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -650,18 +700,18 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.3" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "ring" @@ -678,11 +728,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustix" -version = "0.37.6" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d097081ed288dfe45699b72f5b5d648e5f15d64d900c7080273baa20c16a6849" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ "bitflags", "errno", @@ -706,11 +762,11 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", ] [[package]] @@ -731,22 +787,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.159" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.22", ] [[package]] @@ -787,9 +843,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" dependencies = [ "proc-macro2", "quote", @@ -804,10 +860,11 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall", @@ -817,11 +874,12 @@ dependencies = [ [[package]] name = "tokio" -version = "1.27.0" +version = "1.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "374442f06ee49c3a28a8fc9f01a2596fed7559c6b99b31279c3261778e77d84f" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -843,13 +901,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.22", ] [[package]] @@ -865,9 +923,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", @@ -876,9 +934,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", @@ -981,20 +1039,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", ] @@ -1017,9 +1075,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "untrusted" @@ -1029,11 +1087,10 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -1045,9 +1102,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1055,24 +1112,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1080,28 +1137,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -1152,18 +1209,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1176,42 +1233,42 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/weaver/common/protos-rs/build.rs b/weaver/common/protos-rs/build.rs index 2cbc374348..d128ff1516 100644 --- a/weaver/common/protos-rs/build.rs +++ b/weaver/common/protos-rs/build.rs @@ -7,6 +7,7 @@ fn main() -> Result<(), Box> { .compile( &[ "../protos/relay/datatransfer.proto", + "../protos/relay/asset_transfer.proto", "../protos/relay/events.proto", "../protos/networks/networks.proto", "../protos/driver/driver.proto", diff --git a/weaver/common/protos-rs/pkg/Cargo.lock b/weaver/common/protos-rs/pkg/Cargo.lock new file mode 100644 index 0000000000..993bf77f83 --- /dev/null +++ b/weaver/common/protos-rs/pkg/Cargo.lock @@ -0,0 +1,1059 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.22", +] + +[[package]] +name = "async-trait" +version = "0.1.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.22", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "axum" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" +dependencies = [ + "async-trait", + "axum-core", + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cacti_weaver_protos_rs" +version = "2.0.0-alpha.1" +dependencies = [ + "prost", + "serde", + "tonic", +] + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + +[[package]] +name = "h2" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "matchit" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "object" +version = "0.30.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pin-project" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.22", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quote" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +dependencies = [ + "base64 0.21.2", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "serde" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.22", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "tokio" +version = "1.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374442f06ee49c3a28a8fc9f01a2596fed7559c6b99b31279c3261778e77d84f" +dependencies = [ + "autocfg", + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.22", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tonic" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.13.1", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "prost-derive", + "rustls-pemfile", + "tokio", + "tokio-rustls", + "tokio-stream", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.22", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.22", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.22", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs index 2046cea53b..6fe0056008 100644 --- a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs +++ b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs @@ -208,6 +208,30 @@ pub mod network_client { ); self.inner.unary(request.into_request(), path, codec).await } + /// Asset Transfer endpoints + /// endpoint for a network to request asset transfer to relay state via local relay + pub async fn request_asset_transfer( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/networks.networks.Network/RequestAssetTransfer", + ); + self.inner.unary(request.into_request(), path, codec).await + } /// Event endpoints /// endpoint for a client to subscribe to event via local relay initiating subscription flow. pub async fn subscribe_event( @@ -333,6 +357,15 @@ pub mod network_server { &self, request: tonic::Request, ) -> Result, tonic::Status>; + /// Asset Transfer endpoints + /// endpoint for a network to request asset transfer to relay state via local relay + async fn request_asset_transfer( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; /// Event endpoints /// endpoint for a client to subscribe to event via local relay initiating subscription flow. async fn subscribe_event( @@ -541,6 +574,44 @@ pub mod network_server { }; Box::pin(fut) } + "/networks.networks.Network/RequestAssetTransfer" => { + #[allow(non_camel_case_types)] + struct RequestAssetTransferSvc(pub Arc); + impl tonic::server::UnaryService + for RequestAssetTransferSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).request_asset_transfer(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = RequestAssetTransferSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/networks.networks.Network/SubscribeEvent" => { #[allow(non_camel_case_types)] struct SubscribeEventSvc(pub Arc); diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs b/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs new file mode 100644 index 0000000000..ff141a6304 --- /dev/null +++ b/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs @@ -0,0 +1,592 @@ +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AssetTransferInitializationClaim { + #[prost(string, tag = "1")] + pub asset_asset_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub asset_profile_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub verified_originator_entity_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub verified_beneficiary_entity_id: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub originator_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub beneficiary_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub sender_gateway_network_id: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub recipient_gateway_network_id: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "10")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "11")] + pub sender_gateway_owner_id: ::prost::alloc::string::String, + #[prost(string, tag = "12")] + pub receiver_gateway_owner_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransferCommenceRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub hash_transfer_init_claims: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub hash_prev_message: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub client_transfer_number: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub client_signature: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommenceResponseRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub hash_prev_message: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub server_transfer_number: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub server_signature: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LockAssertionRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub lock_assertion_claim: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub lock_assertion_claim_format: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub lock_assertion_expiration: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub hash_prev_message: ::prost::alloc::string::String, + #[prost(string, tag = "10")] + pub client_transfer_number: ::prost::alloc::string::String, + #[prost(string, tag = "11")] + pub client_signature: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LockAssertionReceiptRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub hash_prev_message: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub server_transfer_number: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub server_signature: ::prost::alloc::string::String, +} +/// Generated client implementations. +pub mod asset_transfer_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct AssetTransferClient { + inner: tonic::client::Grpc, + } + impl AssetTransferClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: std::convert::TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl AssetTransferClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> AssetTransferClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + AssetTransferClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// The sender gateway sends a TransferCommence request to signal to the receiver gateway + /// that the it is ready to start the transfer of the digital asset + pub async fn transfer_commence( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.asset_transfer.AssetTransfer/TransferCommence", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// The receiver gateway sends a CommenceResponse request to the sender gateway to indicate agreement + /// to proceed with the asset transfe + pub async fn commence_response( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.asset_transfer.AssetTransfer/CommenceResponse", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway + /// declaring that the asset in question has been locked or escrowed by the sender gateway in + /// the origin network (e.g. to prevent double spending + pub async fn lock_assertion( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.asset_transfer.AssetTransfer/LockAssertion", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// The receiver gateway sends a LockAssertionReceipt request to the sender gateway to indicate acceptance + /// of the claim(s) delivered by the sender gateway in the previous message + pub async fn lock_assertion_receipt( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.asset_transfer.AssetTransfer/LockAssertionReceipt", + ); + self.inner.unary(request.into_request(), path, codec).await + } + } +} +/// Generated server implementations. +pub mod asset_transfer_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with AssetTransferServer. + #[async_trait] + pub trait AssetTransfer: Send + Sync + 'static { + /// The sender gateway sends a TransferCommence request to signal to the receiver gateway + /// that the it is ready to start the transfer of the digital asset + async fn transfer_commence( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// The receiver gateway sends a CommenceResponse request to the sender gateway to indicate agreement + /// to proceed with the asset transfe + async fn commence_response( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway + /// declaring that the asset in question has been locked or escrowed by the sender gateway in + /// the origin network (e.g. to prevent double spending + async fn lock_assertion( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// The receiver gateway sends a LockAssertionReceipt request to the sender gateway to indicate acceptance + /// of the claim(s) delivered by the sender gateway in the previous message + async fn lock_assertion_receipt( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + } + #[derive(Debug)] + pub struct AssetTransferServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + } + struct _Inner(Arc); + impl AssetTransferServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + let inner = _Inner(inner); + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + } + impl tonic::codegen::Service> for AssetTransferServer + where + T: AssetTransfer, + B: Body + Send + 'static, + B::Error: Into + Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/relay.asset_transfer.AssetTransfer/TransferCommence" => { + #[allow(non_camel_case_types)] + struct TransferCommenceSvc(pub Arc); + impl< + T: AssetTransfer, + > tonic::server::UnaryService + for TransferCommenceSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).transfer_commence(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = TransferCommenceSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.asset_transfer.AssetTransfer/CommenceResponse" => { + #[allow(non_camel_case_types)] + struct CommenceResponseSvc(pub Arc); + impl< + T: AssetTransfer, + > tonic::server::UnaryService + for CommenceResponseSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).commence_response(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommenceResponseSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.asset_transfer.AssetTransfer/LockAssertion" => { + #[allow(non_camel_case_types)] + struct LockAssertionSvc(pub Arc); + impl< + T: AssetTransfer, + > tonic::server::UnaryService + for LockAssertionSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).lock_assertion(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = LockAssertionSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.asset_transfer.AssetTransfer/LockAssertionReceipt" => { + #[allow(non_camel_case_types)] + struct LockAssertionReceiptSvc(pub Arc); + impl< + T: AssetTransfer, + > tonic::server::UnaryService + for LockAssertionReceiptSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).lock_assertion_receipt(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = LockAssertionReceiptSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for AssetTransferServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + } + } + } + impl Clone for _Inner { + fn clone(&self) -> Self { + Self(self.0.clone()) + } + } + impl std::fmt::Debug for _Inner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl tonic::server::NamedService for AssetTransferServer { + const NAME: &'static str = "relay.asset_transfer.AssetTransfer"; + } +} diff --git a/weaver/common/protos-rs/pkg/src/lib.rs b/weaver/common/protos-rs/pkg/src/lib.rs index eff2acbbb3..c77501af32 100644 --- a/weaver/common/protos-rs/pkg/src/lib.rs +++ b/weaver/common/protos-rs/pkg/src/lib.rs @@ -2,6 +2,9 @@ pub mod relay { pub mod datatransfer { include!(concat!("./generated", "/relay.datatransfer.rs")); } + pub mod asset_transfer { + include!(concat!("./generated", "/relay.asset_transfer.rs")); + } pub mod events { include!(concat!("./generated", "/relay.events.rs")); } diff --git a/weaver/common/protos/networks/networks.proto b/weaver/common/protos/networks/networks.proto index befe35d8ad..ab689a975a 100644 --- a/weaver/common/protos/networks/networks.proto +++ b/weaver/common/protos/networks/networks.proto @@ -20,6 +20,10 @@ service Network { // NOTE: This rpc is just for debugging. rpc RequestDatabase(DbName) returns (RelayDatabase) {} + // Asset Transfer endpoints + // endpoint for a network to request asset transfer to relay state via local relay + rpc RequestAssetTransfer(NetworkQuery) returns (common.ack.Ack) {} + // Event endpoints // endpoint for a client to subscribe to event via local relay initiating subscription flow. rpc SubscribeEvent(NetworkEventSubscription) returns (common.ack.Ack) {} diff --git a/weaver/common/protos/relay/asset_transfer.proto b/weaver/common/protos/relay/asset_transfer.proto new file mode 100644 index 0000000000..fa8a230802 --- /dev/null +++ b/weaver/common/protos/relay/asset_transfer.proto @@ -0,0 +1,94 @@ +syntax = "proto3"; + +package relay.asset_transfer; + +import "common/ack.proto"; +import "common/state.proto"; +import "common/query.proto"; + +option java_package = "org.hyperledger.cacti.weaver.protos.relay.datatransfer"; +option go_package = "github.com/hyperledger/cacti/weaver/common/protos-go/v2/relay"; + +service AssetTransfer { + // Stage 2 endpoints + + // The sender gateway sends a TransferCommence request to signal to the receiver gateway + // that the it is ready to start the transfer of the digital asset + rpc TransferCommence(TransferCommenceRequest) returns (common.ack.Ack) {}; + + // The receiver gateway sends a CommenceResponse request to the sender gateway to indicate agreement + // to proceed with the asset transfe + rpc CommenceResponse(CommenceResponseRequest) returns (common.ack.Ack) {}; + + // The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway + // declaring that the asset in question has been locked or escrowed by the sender gateway in + // the origin network (e.g. to prevent double spending + rpc LockAssertion(LockAssertionRequest) returns (common.ack.Ack) {}; + + // The receiver gateway sends a LockAssertionReceipt request to the sender gateway to indicate acceptance + // of the claim(s) delivered by the sender gateway in the previous message + rpc LockAssertionReceipt(LockAssertionReceiptRequest) returns (common.ack.Ack) {}; +} + +message AssetTransferInitializationClaim { + string asset_asset_id = 1; + string asset_profile_id = 2; + string verified_originator_entity_id = 3; + string verified_beneficiary_entity_id = 4; + string originator_pubkey = 5; + string beneficiary_pubkey = 6; + string sender_gateway_network_id = 7; + string recipient_gateway_network_id = 8; + string client_identity_pubkey = 9; + string server_identity_pubkey = 10; + string sender_gateway_owner_id = 11; + string receiver_gateway_owner_id = 12; +} + +message TransferCommenceRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_transfer_init_claims = 6; + string hash_prev_message = 7; + string client_transfer_number = 8; + string client_signature = 9; +} + +message CommenceResponseRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_prev_message = 6; + string server_transfer_number = 7; + string server_signature = 8; +} + +message LockAssertionRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string lock_assertion_claim = 6; + string lock_assertion_claim_format = 7; + string lock_assertion_expiration = 8; + string hash_prev_message = 9; + string client_transfer_number = 10; + string client_signature = 11; +} + +message LockAssertionReceiptRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_prev_message = 6; + string server_transfer_number = 7; + string server_signature = 8; +} \ No newline at end of file diff --git a/weaver/core/relay/Cargo.lock b/weaver/core/relay/Cargo.lock index 61a193aae1..b3be3fab7c 100644 --- a/weaver/core/relay/Cargo.lock +++ b/weaver/core/relay/Cargo.lock @@ -2,20 +2,35 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" [[package]] name = "arrayvec" @@ -25,9 +40,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "async-stream" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad445822218ce64be7a341abfb0b1ea43b5c23aa83902542a4542e78309d8e5e" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", @@ -36,13 +51,13 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] @@ -53,7 +68,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.22", ] [[package]] @@ -64,9 +79,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.12" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f8ccfd9221ee7d1f3d4b33e1f8319b3a81ed8f61f2ea40b37b859794b4491" +checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", @@ -83,7 +98,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustversion", - "serde 1.0.159", + "serde 1.0.164", "sync_wrapper", "tower", "tower-layer", @@ -92,9 +107,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2f958c80c248b34b9a877a643811be8dbca03ca5ba827f2b63baf3a81e5fc4e" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" dependencies = [ "async-trait", "bytes", @@ -107,6 +122,21 @@ dependencies = [ "tower-service", ] +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -121,9 +151,9 @@ checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" [[package]] name = "base64" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "bincode" @@ -131,7 +161,7 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "serde 1.0.159", + "serde 1.0.164", ] [[package]] @@ -142,9 +172,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byteorder" @@ -160,12 +190,10 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cacti_weaver_protos_rs" -version = "2.0.0-alpha-prerelease" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b624ae96a5a9265e603855d3a69555dad230ee98c9da57eaa71547a4d2b8d26d" +version = "2.0.0-alpha.1" dependencies = [ "prost", - "serde 1.0.159", + "serde 1.0.164", "tonic", ] @@ -190,7 +218,7 @@ dependencies = [ "lazy_static", "nom", "rust-ini", - "serde 1.0.159", + "serde 1.0.164", "serde-hjson", "serde_json", "toml", @@ -224,9 +252,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", @@ -237,9 +265,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -261,13 +289,13 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -318,9 +346,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -391,7 +419,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.22", ] [[package]] @@ -435,20 +463,26 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "h2" -version = "0.3.16" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -526,9 +560,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.25" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -575,9 +609,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -604,20 +638,20 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "itertools" @@ -636,9 +670,9 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -664,9 +698,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.140" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "linked-hash-map" @@ -676,9 +710,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "listenfd" @@ -693,9 +727,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -703,12 +737,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "matchit" @@ -724,9 +755,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] @@ -737,16 +768,24 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -775,9 +814,9 @@ dependencies = [ [[package]] name = "nom" -version = "5.1.2" +version = "5.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b" dependencies = [ "lexical-core", "memchr", @@ -812,11 +851,20 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.30.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" @@ -841,7 +889,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.22", ] [[package]] @@ -889,9 +937,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "petgraph" @@ -905,22 +953,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] @@ -937,9 +985,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "ppv-lite86" @@ -959,18 +1007,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.55" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0dd4be24fcdcfeaa12a432d588dc59bbad6cad3510c67e74a2b6b2fc950564" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", "prost-derive", @@ -978,9 +1026,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" dependencies = [ "bytes", "heck", @@ -1000,9 +1048,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools", @@ -1013,18 +1061,18 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ "prost", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -1079,9 +1127,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.3" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", @@ -1090,9 +1138,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "relay" @@ -1105,7 +1153,7 @@ dependencies = [ "futures", "listenfd", "reqwest", - "serde 1.0.159", + "serde 1.0.164", "serde_json", "sled", "tokio", @@ -1116,11 +1164,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.16" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", "bytes", "encoding_rs", "futures-core", @@ -1138,7 +1186,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "serde 1.0.159", + "serde 1.0.164", "serde_json", "serde_urlencoded", "tokio", @@ -1172,18 +1220,24 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustix" -version = "0.37.6" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d097081ed288dfe45699b72f5b5d648e5f15d64d900c7080273baa20c16a6849" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1200,11 +1254,11 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", ] [[package]] @@ -1246,9 +1300,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.8.2" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ "bitflags", "core-foundation", @@ -1259,9 +1313,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" dependencies = [ "core-foundation-sys", "libc", @@ -1275,9 +1329,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" [[package]] name = "serde" -version = "1.0.159" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] @@ -1296,24 +1350,24 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.22", ] [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa", "ryu", - "serde 1.0.159", + "serde 1.0.164", ] [[package]] @@ -1325,7 +1379,7 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde 1.0.159", + "serde 1.0.164", ] [[package]] @@ -1394,9 +1448,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" dependencies = [ "proc-macro2", "quote", @@ -1411,15 +1465,16 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1439,11 +1494,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.27.0" +version = "1.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "374442f06ee49c3a28a8fc9f01a2596fed7559c6b99b31279c3261778e77d84f" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -1451,7 +1507,7 @@ dependencies = [ "pin-project-lite", "socket2", "tokio-macros", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1466,13 +1522,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.22", ] [[package]] @@ -1498,9 +1554,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", @@ -1509,9 +1565,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", @@ -1527,7 +1583,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "serde 1.0.159", + "serde 1.0.164", ] [[package]] @@ -1623,20 +1679,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", ] @@ -1665,9 +1721,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-normalization" @@ -1686,9 +1742,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -1697,9 +1753,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" +checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" dependencies = [ "getrandom", ] @@ -1718,11 +1774,10 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -1734,9 +1789,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1744,24 +1799,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -1771,9 +1826,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1781,28 +1836,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -1857,37 +1912,37 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] @@ -1896,42 +1951,84 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "winreg" version = "0.10.1" diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index e2c646c146..69102fe27b 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -15,12 +15,14 @@ path = "src/client.rs" name = "client-tls" path = "src/client_tls.rs" +[[bin]] +name = "satp-client" +path = "src/satp_client.rs" + [[bin]] name = "dummy-driver" path = "driver/driver.rs" - - [dependencies] tonic = { version="0.8.3", features = ["tls"] } tokio = { version = "1.27", features = ["macros", "fs", "rt", "rt-multi-thread", "sync"] } @@ -34,8 +36,8 @@ futures = { version = "0.3.27" } base64 = "0.20.0" reqwest = { version = "0.11.16", features = ["json"] } serde_json = "1.0.95" -# cacti_weaver_protos_rs = { path = "./protos-rs" } -cacti_weaver_protos_rs = "2.0.0-alpha.1" +# cacti_weaver_protos_rs = "2.0.0-alpha.1" +cacti_weaver_protos_rs = { path = "../../common/protos-rs/pkg" } [build-dependencies] tonic-build = "0.8.4" diff --git a/weaver/core/relay/src/satp_client.rs b/weaver/core/relay/src/satp_client.rs new file mode 100644 index 0000000000..dcf99d21d4 --- /dev/null +++ b/weaver/core/relay/src/satp_client.rs @@ -0,0 +1,59 @@ +mod relay_proto; +use futures::future::{BoxFuture, FutureExt}; +use weaverpb::common::ack::ack; +use weaverpb::common::state::{request_state, view_payload, ViewPayload, View, Meta, meta}; +use weaverpb::common::events::{event_subscription_state, EventMatcher, EventPublication, event_publication, ContractTransaction}; +use weaverpb::relay::events::{event_publish_client::EventPublishClient}; +use weaverpb::networks::networks::{network_client::NetworkClient, GetStateMessage, NetworkQuery, NetworkEventSubscription, NetworkEventUnsubscription}; +use relay_proto::get_url; +use std::env; +use std::thread::sleep; +use std::time; +use serde_json; + +#[tokio::main] +async fn main() -> Result<(), Box> { + println!("\nAsset Transfer Test"); + asset_transfer().await?; + Ok(()) +} + +async fn asset_transfer() -> Result<(), Box> { + let args: Vec = env::args().collect(); + let net_addr = format!("http://{}", get_url(&args)); + let mut network_client = NetworkClient::connect(net_addr).await?; + // localhost:9081/Corda_Network/test + // {locationsegment}/{Network_id}/{query} + // localhost:9081/Corda_Network/mychannel:simplestate:read:TestState + let request = tonic::Request::new(NetworkQuery { + policy: vec!["test".to_string()], + address: args[2].to_string(), + requesting_relay: "".to_string(), + requesting_network: "".to_string(), + requesting_org: "".to_string(), + certificate: "test".to_string(), + requestor_signature: "test".to_string(), + nonce: "test".to_string(), + confidential: false, + }); + let response = network_client.request_asset_transfer(request).await?; + println!("RESPONSE={:?}", response); + + match ack::Status::from_i32(response.get_ref().status) { + Some(ack_status) => match ack_status { + ack::Status::Ok => { + //poll_for_asset_state(request_id.to_string(), network_client, 0).await; + println!("Asset Transfer: Success!"); + } + ack::Status::Error => { + println!("An error occurred in request_asset_transfer call"); + std::process::exit(1); + } + }, + None => { + println!("The returned Ack has no status"); + std::process::exit(1); + } + } + Ok(()) +} diff --git a/weaver/core/relay/src/services/asset_transfer_service.rs b/weaver/core/relay/src/services/asset_transfer_service.rs new file mode 100644 index 0000000000..8f49d9ffd9 --- /dev/null +++ b/weaver/core/relay/src/services/asset_transfer_service.rs @@ -0,0 +1,127 @@ +// Internal generated modules +use weaverpb::common::ack::{ack, Ack}; +use weaverpb::common::query::Query; +use weaverpb::common::state::{request_state, view_payload, RequestState, ViewPayload}; +use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; +use weaverpb::relay::datatransfer::data_transfer_server::DataTransfer; +// Internal modules +use crate::db::Database; +use crate::error::Error; +use crate::relay_proto::{parse_address, LocationSegment}; +use crate::services::helpers::{get_driver, get_driver_client}; +use crate::services::types::{Driver}; +// external modules +use config; +use tokio::sync::RwLock; +use tonic::{Request, Response, Status}; + +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; + +#[derive(Debug, Default)] +pub struct AssetTransferService { + pub config_lock: RwLock, +} + +/// AssetTransferService is the gRPC server implementation that handles the logic for +/// communication of the asset transfer protocol between two gateways. +#[tonic::async_trait] +impl AssetTransfer for AssetTransferService { + async fn transfer_commence( + &self, + request: Request + ) -> Result, Status> { + println!( + "Got a transfer commence request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let transfer_commence_request = request.into_inner().clone(); + let conf = self.config_lock.read().await; + + // Database access/storage + let db = Database { + db_path: conf.get_str("db_path").unwrap(), + db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, + db_open_retry_backoff_msec: conf + .get_int("db_open_retry_backoff_msec") + .unwrap_or(10) as u32, + }; + + match transfer_commence_helper(db, transfer_commence_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + println!("Transfer commence failed."); + let reply = Ok( + // TODO: remove the hardcoded value + Response::new(Ack { + status: ack::Status::Error as i32, + request_id: "xxxxxxxxx".to_string(), + message: format!("Error: Transfer initiation failed. {:?}", e), + }) + ); + println!("Sending back Ack: {:?}\n", reply); + reply + } + } + } + +} + +/// transfer_commence_helper is run on the receiving gateway to initiate asset transfer protocol that was +/// requested from the requesting gateway +pub fn transfer_commence_helper( + db: Database, + transfer_commence_request: TransferCommenceRequest, + conf: config::Config +) -> Result { + let _set_query = db + .set(&transfer_commence_request.session_id.to_string(), &transfer_commence_request.session_id) + .map_err(|e| Error::Simple(format!("DB Failure: {:?}", e)))?; + + //TODO remove hardcoded value + let network_id = "Dummy_Network"; + let result = get_driver(network_id.to_string(), conf.clone()); + match result { + Ok(driver_info) => { + spawn_transfer_commence_request( + initialization_request, + &driver_info, + conf.clone() + ); + // TODO: remove the hardcoded value + return Ok(Ack { + status: ack::Status::Ok as i32, + request_id: "xxxxxxxx".to_string(), + message: driver_info.hostname.to_string(), + }); + } + Err(e) => Err(e), + } +} + +// Function that starts a thread which checks the transfer initialization request +fn spawn_transfer_commence_request( + transfer_commence_request: TransferCommenceRequest, + driver_info: &Driver, + conf: config::Config +) { + tokio::spawn(async move { + let is_valid_request = check_transfer_commence_request(initialization_request.clone()); + if is_valid_request { + // Send an InitiationResponse message to the requesting gateway + println!("The asset initiation request is valid\n"); + } else { + // Send an InitiationDenied message to the requesting gateway + println!("The asset initiation request is denied\n"); + } + }); +} + +fn check_transfer_commence_request(transfer_commence_request: TransferCommenceRequest) -> bool { + true +} \ No newline at end of file diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 0f4d14e0e2..2b10d54960 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -5,7 +5,9 @@ use weaverpb::common::state::{request_state, RequestState}; use weaverpb::common::events::{EventSubscription, event_subscription_state, EventSubscriptionState, EventSubOperation, event_publication, EventPublication, EventStates}; use weaverpb::networks::networks::network_server::Network; use weaverpb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription, NetworkEventUnsubscription}; +use weaverpb::relay::asset_transfer::TransferCommenceRequest; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; +use weaverpb::relay::asset_transfer::asset_transfer_client::AssetTransferClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::relay_proto::{parse_address, LocationSegment}; // Internal modules @@ -194,6 +196,88 @@ impl Network for NetworkService { } } + /// request_asset_transfer is called from the client to query the requesting relay for the state + /// Since this request is async w.r.t the network, the request info/state machine is + /// stored in a db on the requesting relay (status polled using get_state) + async fn request_asset_transfer(&self, request: Request) -> Result, Status> { + println!( + "Got a NetworkQuery request from {:?} - {:?}", + request.remote_addr(), + request + ); + let conf = self.config_lock.read().await.clone(); + // Database access/storage + let db = Database { + db_path: conf.get_str("db_path").unwrap(), + db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, + db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + }; + + let request_id = Uuid::new_v4(); + // Initial request state stored in DB. + let target: RequestState = RequestState { + status: request_state::Status::PendingAck as i32, + request_id: request_id.to_string(), + state: None, + }; + let message_insert = db.set(&request_id.to_string(), &target); + // Kept this as a match as the error case returns an Ok. + match message_insert { + Ok(_) => println!( + "Successfully stored NetworkQuery in db with request_id: {}", + request_id.to_string() + ), + Err(e) => { + // Internal failure of sled. Send Error response + println!( + "Error storing NetworkQuery in db for request_id: {}", + request_id.to_string() + ); + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("{:?}", e), + })); + println!("Sending Ack back to network: {:?}\n", reply); + return reply; + } + } + + let network_query = request.into_inner().clone(); + let parsed_address = parse_address(network_query.address.to_string()); + match parsed_address { + Ok(address) => { + // TODO: verify that host and port are valid + // Spawns a child process to handle sending request + spawn_send_asset_transfer_request( + conf, + network_query, + request_id.to_string(), + address.location.hostname.to_string(), + address.location.port.to_string() + ); + // Send Ack back to network while request is happening in a thread + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "".to_string(), + }; + println!("Sending Ack back to network: {:?}\n", reply); + Ok(Response::new(reply)) + } + Err(e) => { + println!("Invalid Address"); + let reply = Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: {:?}", e), + }; + println!("Sending Ack back to network: {:?}\n", reply); + Ok(Response::new(reply)) + } + } + } + // Subscribe Event Endpoints async fn subscribe_event(&self, request: Request) -> Result, Status> { println!( @@ -690,6 +774,167 @@ async fn data_transfer_call( Ok(response) } +// Sends a request to the remote relay +fn spawn_send_asset_transfer_request( + conf: config::Config, + network_query: NetworkQuery, + request_id: String, + relay_host: String, + relay_port: String, +) { + println!("Sending Query to remote relay: {:?}:{:?}", relay_host, relay_port); + // Locally scoped function to update request status in db. This function is + // called for the first time after an Ack is received from the remote relay. + // A locally created RequestState with status Pending or Error is stored. + // When a response is received from the remote relay it will write the + // returned RequestState with status Completed or Error. + fn update_request_status( + curr_request_id: String, + new_status: request_state::Status, + curr_db_path: String, + db_open_max_retries: u32, + db_open_retry_backoff_msec: u32, + state: Option, + ) { + let db = Database { + db_path: curr_db_path, + db_open_max_retries: db_open_max_retries, + db_open_retry_backoff_msec: db_open_retry_backoff_msec, + }; + let target: RequestState = RequestState { + status: new_status as i32, + request_id: curr_request_id.clone(), + state, + }; + + // Panic if this fails, atm the panic is just logged by the tokio runtime + db.set(&curr_request_id, &target) + .expect("Failed to insert into DB"); + println!("Successfully written RequestState to database"); + println!("{:?}\n", db.get::(curr_request_id).unwrap()) + } + // Spawning new thread to make the data_transfer_call to remote relay + tokio::spawn(async move { + let db_path = conf.get_str("db_path").unwrap(); + + // Iterate through the relay entries in the configuration to find a match + let relays_table = conf.get_table("relays").unwrap(); + let mut relay_tls = false; + let mut relay_tlsca_cert_path = "".to_string(); + for (_relay_name, relay_spec) in relays_table { + let relay_uri = relay_spec.clone().try_into::().unwrap(); + if relay_host == relay_uri.hostname && relay_port == relay_uri.port { + relay_tls = relay_uri.tls; + relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + } + } + + let result = asset_transfer_call( + conf.get_str("name").unwrap(), + relay_host, + relay_port, + network_query, + request_id.clone(), + relay_tls, + relay_tlsca_cert_path.to_string(), + ) + .await; + println!("Received Ack from remote relay: {:?}\n", result); + // Potentially clean up when more skilled at Rust. + // Updates the request in the DB depending on the response status from the remote relay + match result { + Ok(ack_response) => { + let ack_response_into_inner = ack_response.into_inner().clone(); + // This match first checks if the status is valid. + match ack::Status::from_i32(ack_response_into_inner.status) { + Some(status) => match status { + ack::Status::Ok => update_request_status( + request_id.to_string(), + request_state::Status::Pending, + db_path.to_string(), + conf.get_int("db_open_max_retries").unwrap_or(500) as u32, + conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + None, + ), + ack::Status::Error => update_request_status( + request_id.to_string(), + request_state::Status::Error, + db_path.to_string(), + conf.get_int("db_open_max_retries").unwrap_or(500) as u32, + conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + Some(request_state::State::Error( + ack_response_into_inner.message.to_string(), + )), + ), + }, + None => update_request_status( + request_id.to_string(), + request_state::Status::Error, + db_path.to_string(), + conf.get_int("db_open_max_retries").unwrap_or(500) as u32, + conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + Some(request_state::State::Error( + "Status is not supported or is invalid".to_string(), + )), + ), + } + } + Err(result_error) => update_request_status( + request_id.to_string(), + request_state::Status::Error, + db_path.to_string(), + conf.get_int("db_open_max_retries").unwrap_or(500) as u32, + conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + Some(request_state::State::Error(format!("{:?}", result_error))), + ), + } + }); +} +// Call to remote relay for the data transfer protocol. +async fn asset_transfer_call( + relay_name: String, + relay_host: String, + relay_port: String, + network_query: NetworkQuery, + request_id: String, + use_tls: bool, + tlsca_cert_path: String, +) -> Result, Box> { + let client_addr = format!("http://{}:{}", relay_host, relay_port); + let mut client; + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await?; + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(relay_host); + + let channel = Channel::from_shared(client_addr)? + .tls_config(tls)? + .connect() + .await?; + + client = AssetTransferClient::new(channel); + } else { + client = AssetTransferClient::connect(client_addr).await?; + } + let transfer_commence_request = tonic::Request::new(TransferCommenceRequest { + message_type: todo!(), + session_id: todo!(), + transfer_context_id: todo!(), + client_identity_pubkey: todo!(), + server_identity_pubkey: todo!(), + hash_transfer_init_claims: todo!(), + hash_prev_message: todo!(), + client_transfer_number: todo!(), + client_signature: todo!(), + }); + println!("Transfer commence request: {:?}", transfer_commence_request); + let response = client.transfer_commence(transfer_commence_request).await?; + Ok(response) +} + // Sends a request to the remote relay fn spawn_send_event_subscription_request( From 235e7a40c6bf9fb462a30301815ddae5b6dbf860 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Fri, 30 Jun 2023 10:37:50 +0100 Subject: [PATCH 02/59] initial commit --- .../pkg/src/generated/relay.asset_transfer.rs | 3 +- .../common/protos/relay/asset_transfer.proto | 3 +- weaver/core/relay/Cargo.lock | 17 +- weaver/core/relay/config/Corda_Relay.toml | 2 + weaver/core/relay/config/Corda_Relay2.toml | 2 + weaver/core/relay/config/Dummy_Relay.toml | 2 + weaver/core/relay/config/Dummy_Relay_tls.toml | 2 + weaver/core/relay/config/Fabric_Relay.toml | 2 + weaver/core/relay/config/Fabric_Relay2.toml | 2 + weaver/core/relay/config/Settings.toml | 2 + weaver/core/relay/src/main.rs | 7 + .../src/services/asset_transfer_service.rs | 238 ++++++++++++++---- weaver/core/relay/src/services/mod.rs | 1 + .../relay/src/services/network_service.rs | 81 +++--- 14 files changed, 272 insertions(+), 92 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs b/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs index ff141a6304..bcf6e36f1e 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs @@ -1,7 +1,7 @@ #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct AssetTransferInitializationClaim { +pub struct AssetTransferInitializationClaims { #[prost(string, tag = "1")] pub asset_asset_id: ::prost::alloc::string::String, #[prost(string, tag = "2")] @@ -47,6 +47,7 @@ pub struct TransferCommenceRequest { pub hash_prev_message: ::prost::alloc::string::String, #[prost(string, tag = "8")] pub client_transfer_number: ::prost::alloc::string::String, + /// AssetTransferInitializationClaims asset_transfer_initialization_claims = 10; #[prost(string, tag = "9")] pub client_signature: ::prost::alloc::string::String, } diff --git a/weaver/common/protos/relay/asset_transfer.proto b/weaver/common/protos/relay/asset_transfer.proto index fa8a230802..dbded4b908 100644 --- a/weaver/common/protos/relay/asset_transfer.proto +++ b/weaver/common/protos/relay/asset_transfer.proto @@ -30,7 +30,7 @@ service AssetTransfer { rpc LockAssertionReceipt(LockAssertionReceiptRequest) returns (common.ack.Ack) {}; } -message AssetTransferInitializationClaim { +message AssetTransferInitializationClaims { string asset_asset_id = 1; string asset_profile_id = 2; string verified_originator_entity_id = 3; @@ -55,6 +55,7 @@ message TransferCommenceRequest { string hash_prev_message = 7; string client_transfer_number = 8; string client_signature = 9; + // AssetTransferInitializationClaims asset_transfer_initialization_claims = 10; } message CommenceResponseRequest { diff --git a/weaver/core/relay/Cargo.lock b/weaver/core/relay/Cargo.lock index b3be3fab7c..e0873a2b4c 100644 --- a/weaver/core/relay/Cargo.lock +++ b/weaver/core/relay/Cargo.lock @@ -509,15 +509,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.1" @@ -642,7 +633,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", "windows-sys 0.48.0", ] @@ -843,11 +834,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] diff --git a/weaver/core/relay/config/Corda_Relay.toml b/weaver/core/relay/config/Corda_Relay.toml index ea47a43179..76a27993d5 100644 --- a/weaver/core/relay/config/Corda_Relay.toml +++ b/weaver/core/relay/config/Corda_Relay.toml @@ -3,8 +3,10 @@ port="9081" host="localhost" hostname="localhost" db_path="db/Corda_Relay/requests" +satp_db_path="satp_db/Corda_Relay/requests" # This will be replaced by the task queue. remote_db_path="db/Corda_Relay/remote_request" +remote_satp_db_path="satp_db/Corda_Relay/remote_request" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Corda_Relay2.toml b/weaver/core/relay/config/Corda_Relay2.toml index 84293fe036..9912ca261c 100644 --- a/weaver/core/relay/config/Corda_Relay2.toml +++ b/weaver/core/relay/config/Corda_Relay2.toml @@ -3,8 +3,10 @@ port="9082" host="localhost" hostname="localhost" db_path="db/Corda_Relay2/requests" +satp_db_path="satp_db/Corda_Relay2/requests" # This will be replaced by the task queue. remote_db_path="db/Corda_Relay2/remote_request" +remote_satp_db_path="satp_db/Corda_Relay2/remote_request" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Dummy_Relay.toml b/weaver/core/relay/config/Dummy_Relay.toml index 5d68da9440..89b194683c 100644 --- a/weaver/core/relay/config/Dummy_Relay.toml +++ b/weaver/core/relay/config/Dummy_Relay.toml @@ -2,8 +2,10 @@ name = "Dummy_Relay" port="9085" hostname="localhost" db_path="db/Dummy_Relay/requests" +satp_db_path="satp_db/Dummy_Relay/requests" # This will be replaced by the task queue. remote_db_path="db/Dummy_Relay/remote_request" +remote_satp_db_path="satp_db/Dummy_Relay/remote_request" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Dummy_Relay_tls.toml b/weaver/core/relay/config/Dummy_Relay_tls.toml index 17677e6f2c..b36121651c 100644 --- a/weaver/core/relay/config/Dummy_Relay_tls.toml +++ b/weaver/core/relay/config/Dummy_Relay_tls.toml @@ -2,8 +2,10 @@ name = "Dummy_Relay" port="9085" hostname="localhost" db_path="db/Dummy_Relay_tls/requests" +satp_db_path="satp_db/Dummy_Relay_tls/requests" # This will be replaced by the task queue. remote_db_path="db/Dummy_Relay_tls/remote_request" +remote_satp_db_path="satp_db/Dummy_Relay_tls/remote_request" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Fabric_Relay.toml b/weaver/core/relay/config/Fabric_Relay.toml index 98536a597d..82d513bf94 100644 --- a/weaver/core/relay/config/Fabric_Relay.toml +++ b/weaver/core/relay/config/Fabric_Relay.toml @@ -2,8 +2,10 @@ name = "Fabric_Relay" port="9080" hostname="localhost" db_path="db/Fabric_Relay/requests" +satp_db_path="satp_db/Fabric_Relay/requests" # This will be replaced by the task queue. remote_db_path="db/Fabric_Relay/remote_request" +remote_satp_db_path="satp_db/Fabric_Relay/remote_request" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Fabric_Relay2.toml b/weaver/core/relay/config/Fabric_Relay2.toml index 995f7250e8..86debc7b7a 100644 --- a/weaver/core/relay/config/Fabric_Relay2.toml +++ b/weaver/core/relay/config/Fabric_Relay2.toml @@ -2,8 +2,10 @@ name = "Fabric_Relay2" port="9083" hostname="localhost" db_path="db/Fabric_Relay2/requests" +satp_db_path="satp_db/Fabric_Relay2/requests" # This will be replaced by the task queue. remote_db_path="db/Fabric_Relay2/remote_request" +remote_satp_db_path="satp_db/Fabric_Relay2/remote_request" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Settings.toml b/weaver/core/relay/config/Settings.toml index 4628dba61f..c303ed3b4f 100644 --- a/weaver/core/relay/config/Settings.toml +++ b/weaver/core/relay/config/Settings.toml @@ -2,8 +2,10 @@ name = "Fabric_Relay" port="9080" hostname="localhost" db_path="db/requests" +satp_db_path="satp_db/requests" # This will be replaced by the task queue. remote_db_path="db/remote_requests" +remote_satp_db_path="satp_db/remote_requests" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/src/main.rs b/weaver/core/relay/src/main.rs index 6e1e05e171..2efbe46b02 100644 --- a/weaver/core/relay/src/main.rs +++ b/weaver/core/relay/src/main.rs @@ -1,11 +1,13 @@ // Internal generated modules use weaverpb::networks::networks::network_server::NetworkServer; +use weaverpb::relay::asset_transfer::asset_transfer_server::AssetTransferServer; use weaverpb::relay::datatransfer::data_transfer_server::DataTransferServer; use weaverpb::relay::events::event_subscribe_server::EventSubscribeServer; use weaverpb::relay::events::event_publish_server::EventPublishServer; // Internal modules use services::data_transfer_service::DataTransferService; +use services::asset_transfer_service::AssetTransferService; use services::event_subscribe_service::EventSubscribeService; use services::event_publish_service::EventPublishService; use services::network_service::NetworkService; @@ -54,6 +56,9 @@ async fn main() -> Result<(), Box> { let relay = DataTransferService { config_lock: RwLock::new(settings.clone()), }; + let gateway = AssetTransferService { + config_lock: RwLock::new(settings.clone()), + }; let event_subscribe = EventSubscribeService { config_lock: RwLock::new(settings.clone()), }; @@ -73,6 +78,7 @@ async fn main() -> Result<(), Box> { let server = Server::builder() .tls_config(ServerTlsConfig::new().identity(identity))? .add_service(DataTransferServer::new(relay)) + .add_service(AssetTransferServer::new(gateway)) .add_service(EventSubscribeServer::new(event_subscribe)) .add_service(EventPublishServer::new(event_publish)) .add_service(NetworkServer::new(network)); @@ -81,6 +87,7 @@ async fn main() -> Result<(), Box> { // Spins up two gRPC services in a tonic server. One for relay to relay and one for network to relay communication. let server = Server::builder() .add_service(DataTransferServer::new(relay)) + .add_service(AssetTransferServer::new(gateway)) .add_service(EventSubscribeServer::new(event_subscribe)) .add_service(EventPublishServer::new(event_publish)) .add_service(NetworkServer::new(network)); diff --git a/weaver/core/relay/src/services/asset_transfer_service.rs b/weaver/core/relay/src/services/asset_transfer_service.rs index 8f49d9ffd9..88bc26781d 100644 --- a/weaver/core/relay/src/services/asset_transfer_service.rs +++ b/weaver/core/relay/src/services/asset_transfer_service.rs @@ -1,15 +1,14 @@ // Internal generated modules use weaverpb::common::ack::{ack, Ack}; -use weaverpb::common::query::Query; -use weaverpb::common::state::{request_state, view_payload, RequestState, ViewPayload}; -use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; -use weaverpb::relay::datatransfer::data_transfer_server::DataTransfer; +use weaverpb::relay::asset_transfer::asset_transfer_client::AssetTransferClient; +use weaverpb::relay::asset_transfer::asset_transfer_server::AssetTransfer; +use weaverpb::relay::asset_transfer::{TransferCommenceRequest, CommenceResponseRequest, LockAssertionRequest, LockAssertionReceiptRequest}; + // Internal modules use crate::db::Database; use crate::error::Error; -use crate::relay_proto::{parse_address, LocationSegment}; -use crate::services::helpers::{get_driver, get_driver_client}; -use crate::services::types::{Driver}; +use crate::relay_proto::{LocationSegment}; + // external modules use config; use tokio::sync::RwLock; @@ -23,9 +22,11 @@ pub struct AssetTransferService { } /// AssetTransferService is the gRPC server implementation that handles the logic for -/// communication of the asset transfer protocol between two gateways. +/// communication of the asset transfer protocol SATP between two gateways. #[tonic::async_trait] impl AssetTransfer for AssetTransferService { + /// transfer_commence is run on the receiver gateway to allow the sender gateway to signal to the + /// receiver gateway that it is ready to start the transfer of the digital asset async fn transfer_commence( &self, request: Request @@ -40,18 +41,20 @@ impl AssetTransfer for AssetTransferService { let conf = self.config_lock.read().await; // Database access/storage - let db = Database { - db_path: conf.get_str("db_path").unwrap(), + let remote_satp_db = Database { + db_path: conf.get_str("satp_db_path").unwrap(), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, db_open_retry_backoff_msec: conf .get_int("db_open_retry_backoff_msec") .unwrap_or(10) as u32, }; + // TODO replace the session_id with request_id + let request_id = transfer_commence_request.session_id.to_string(); - match transfer_commence_helper(db, transfer_commence_request, conf.clone()) { + match transfer_commence_helper(remote_satp_db, &request_id, transfer_commence_request, conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); - println!("Sending back Ack: {:?}\n", reply); + println!("Sending Ack of transfer commence request back: {:?}\n", reply); reply } Err(e) => { @@ -60,7 +63,7 @@ impl AssetTransfer for AssetTransferService { // TODO: remove the hardcoded value Response::new(Ack { status: ack::Status::Error as i32, - request_id: "xxxxxxxxx".to_string(), + request_id: request_id.to_string(), message: format!("Error: Transfer initiation failed. {:?}", e), }) ); @@ -70,54 +73,201 @@ impl AssetTransfer for AssetTransferService { } } + async fn commence_response( + &self, + request: Request + ) -> Result, Status> { + println!( + "Got a commence response request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let reply = Ok( + Response::new(Ack { + status: ack::Status::Error as i32, + request_id: "xxxxxxxxx".to_string(), + message: format!("Error: Not implemented yet."), + }) + ); + println!("Sending back Ack: {:?}\n", reply); + reply + } + + async fn lock_assertion( + &self, + request: Request + ) -> Result, Status> { + println!( + "Got a lock assertion request from {:?} - {:?}", + request.remote_addr(), + request + ); + let reply = Ok( + Response::new(Ack { + status: ack::Status::Error as i32, + request_id: "xxxxxxxxx".to_string(), + message: format!("Error: Not implemented yet."), + }) + ); + println!("Sending back Ack: {:?}\n", reply); + reply + } + + async fn lock_assertion_receipt( + &self, + request: Request + ) -> Result, Status> { + println!( + "Got a lock assertion receipt request from {:?} - {:?}", + request.remote_addr(), + request + ); + let reply = Ok( + Response::new(Ack { + status: ack::Status::Error as i32, + request_id: "xxxxxxxxx".to_string(), + message: format!("Error: Not implemented yet."), + }) + ); + println!("Sending back Ack: {:?}\n", reply); + reply + } } /// transfer_commence_helper is run on the receiving gateway to initiate asset transfer protocol that was /// requested from the requesting gateway pub fn transfer_commence_helper( - db: Database, + remote_satp_db: Database, + request_id: &String, transfer_commence_request: TransferCommenceRequest, conf: config::Config ) -> Result { - let _set_query = db - .set(&transfer_commence_request.session_id.to_string(), &transfer_commence_request.session_id) + + let _set_query = remote_satp_db + .set(&request_id.to_string(), &transfer_commence_request) .map_err(|e| Error::Simple(format!("DB Failure: {:?}", e)))?; - //TODO remove hardcoded value - let network_id = "Dummy_Network"; - let result = get_driver(network_id.to_string(), conf.clone()); - match result { - Ok(driver_info) => { - spawn_transfer_commence_request( - initialization_request, - &driver_info, - conf.clone() - ); - // TODO: remove the hardcoded value - return Ok(Ack { - status: ack::Status::Ok as i32, - request_id: "xxxxxxxx".to_string(), - message: driver_info.hostname.to_string(), - }); + let is_valid_request = check_transfer_commence_request(transfer_commence_request.clone()); + + if is_valid_request { + println!("The transfer commence request is valid\n"); + match send_commence_response_helper(&request_id, remote_satp_db, conf) { + Ok(ack) => { + println!("Ack transfer commence request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + println!("Transfer commence request failed."); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: Transfer commence request failed. {:?}", e), + }); + } } - Err(e) => Err(e), + + } else { + println!("The transfer commence request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Invalid transfer commence request".to_string(), + }); } } -// Function that starts a thread which checks the transfer initialization request -fn spawn_transfer_commence_request( - transfer_commence_request: TransferCommenceRequest, - driver_info: &Driver, +fn send_commence_response_helper( + request_id: &String, + remote_satp_db: Database, conf: config::Config -) { +) -> Result { + let transfer_commence_request: TransferCommenceRequest = remote_satp_db + .get::(request_id.to_string()) + .map_err(|e| Error::GetQuery(format!("Failed to get transfer commence request from db. Error: {:?}", e)))?; + let relays_table = conf.get_table("relays")?; + // let relay_uri = relays_table + // .get(&transfer_commence_request.requesting_relay.to_string()) + // .ok_or(Error::Simple("Relay name not found".to_string()))?; + // TODO: + let relay_uri = relays_table + .get(&"Dummy_Relay".to_string()) + .ok_or(Error::Simple("Relay name not found".to_string()))?; + let uri = relay_uri.clone().try_into::()?; + + let commence_response_request = CommenceResponseRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + hash_prev_message: "hash_prev_message1".to_string(), + server_transfer_number: "server_transfer_number1".to_string(), + server_signature: "server_signature1".to_string(), + }; + + spawn_send_commence_response( + commence_response_request, + uri.hostname.to_string(), + uri.port.to_string(), + uri.tls, + uri.tlsca_cert_path.to_string(), + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "".to_string(), + }; + + return Ok(reply); +} + +fn spawn_send_commence_response(commence_response_request: CommenceResponseRequest, requestor_host: String, requester_port: String, use_tls: bool, tlsca_cert_path: String) { tokio::spawn(async move { - let is_valid_request = check_transfer_commence_request(initialization_request.clone()); - if is_valid_request { - // Send an InitiationResponse message to the requesting gateway - println!("The asset initiation request is valid\n"); + println!("Sending state back to sending gateway: Request ID = {:?}", commence_response_request.session_id); + // match state.state.as_ref().unwrap() { + // view_payload::State::View(v) => println!("View Meta: {:?}, View Data: {:?}", v.meta, base64::encode(&v.data)), + // view_payload::State::Error(e) => println!("Error: {:?}", e), + // } + let client_addr = format!("http://{}:{}", requestor_host, requester_port); + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(requestor_host); + + let channel = Channel::from_shared(client_addr.to_string()).unwrap() + .tls_config(tls).expect(&format!("Error in TLS configuration for client: {}", client_addr.to_string())) + .connect() + .await + .unwrap(); + + let mut client_result = AssetTransferClient::new(channel); + let response = client_result.commence_response(commence_response_request).await; + println!("Response ACK from sending gateway={:?}\n", response); } else { - // Send an InitiationDenied message to the requesting gateway - println!("The asset initiation request is denied\n"); + let client_result = AssetTransferClient::connect(client_addr).await; + match client_result { + Ok(client) => { + let response = client.clone().commence_response(commence_response_request).await; + println!("Response ACK from sending gateway={:?}\n", response); + // Not returning anything here + } + Err(e) => { + // TODO: Add better error handling (Attempt a few times?) + println!( + "Failed to connect to client: ${:?}. Error: {}\n", + requester_port, + e.to_string() + ); + // TODO: Handle this error thorugh join handle after thread completes. + // Not actually returning anything here yet + } + } } }); } diff --git a/weaver/core/relay/src/services/mod.rs b/weaver/core/relay/src/services/mod.rs index dde7ea28b1..327e85b08e 100644 --- a/weaver/core/relay/src/services/mod.rs +++ b/weaver/core/relay/src/services/mod.rs @@ -1,4 +1,5 @@ pub mod data_transfer_service; +pub mod asset_transfer_service; pub mod network_service; pub mod event_subscribe_service; pub mod event_publish_service; diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 2b10d54960..54675e3fb8 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -5,7 +5,7 @@ use weaverpb::common::state::{request_state, RequestState}; use weaverpb::common::events::{EventSubscription, event_subscription_state, EventSubscriptionState, EventSubOperation, event_publication, EventPublication, EventStates}; use weaverpb::networks::networks::network_server::Network; use weaverpb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription, NetworkEventUnsubscription}; -use weaverpb::relay::asset_transfer::TransferCommenceRequest; +use weaverpb::relay::asset_transfer::{TransferCommenceRequest, AssetTransferInitializationClaims}; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; use weaverpb::relay::asset_transfer::asset_transfer_client::AssetTransferClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; @@ -196,9 +196,8 @@ impl Network for NetworkService { } } - /// request_asset_transfer is called from the client to query the requesting relay for the state - /// Since this request is async w.r.t the network, the request info/state machine is - /// stored in a db on the requesting relay (status polled using get_state) + /// request_asset_transfer is called from the client to query the sending gateway to transfer an asset. + /// the request info/state machine is stored in a db on the sending gateway async fn request_asset_transfer(&self, request: Request) -> Result, Status> { println!( "Got a NetworkQuery request from {:?} - {:?}", @@ -207,8 +206,8 @@ impl Network for NetworkService { ); let conf = self.config_lock.read().await.clone(); // Database access/storage - let db = Database { - db_path: conf.get_str("db_path").unwrap(), + let satp_db = Database { + db_path: conf.get_str("satp_db_path").unwrap(), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, }; @@ -220,25 +219,25 @@ impl Network for NetworkService { request_id: request_id.to_string(), state: None, }; - let message_insert = db.set(&request_id.to_string(), &target); + let message_insert = satp_db.set(&request_id.to_string(), &target); // Kept this as a match as the error case returns an Ok. match message_insert { Ok(_) => println!( - "Successfully stored NetworkQuery in db with request_id: {}", + "Successfully stored NetworkQuery in satp_db with request_id: {}", request_id.to_string() ), Err(e) => { // Internal failure of sled. Send Error response println!( - "Error storing NetworkQuery in db for request_id: {}", + "Error storing NetworkQuery in satp_db for request_id: {}", request_id.to_string() ); let reply = Ok(Response::new(Ack { status: ack::Status::Error as i32, request_id: request_id.to_string(), - message: format!("{:?}", e), + message: format!("Error storing NetworkQuery in satp_db {:?}", e), })); - println!("Sending Ack back to network: {:?}\n", reply); + println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); return reply; } } @@ -262,7 +261,7 @@ impl Network for NetworkService { request_id: request_id.to_string(), message: "".to_string(), }; - println!("Sending Ack back to network: {:?}\n", reply); + println!("Sending Ack of the asset transfer request back to network: {:?}\n", reply); Ok(Response::new(reply)) } Err(e) => { @@ -272,7 +271,7 @@ impl Network for NetworkService { request_id: request_id.to_string(), message: format!("Error: {:?}", e), }; - println!("Sending Ack back to network: {:?}\n", reply); + println!("Sending Ack back with an error to network: {:?}\n", reply); Ok(Response::new(reply)) } } @@ -774,7 +773,7 @@ async fn data_transfer_call( Ok(response) } -// Sends a request to the remote relay +// Sends a request to the receiving gateway fn spawn_send_asset_transfer_request( conf: config::Config, network_query: NetworkQuery, @@ -782,11 +781,11 @@ fn spawn_send_asset_transfer_request( relay_host: String, relay_port: String, ) { - println!("Sending Query to remote relay: {:?}:{:?}", relay_host, relay_port); + println!("Sending asset transfer request to receiving gateway: {:?}:{:?}", relay_host, relay_port); // Locally scoped function to update request status in db. This function is - // called for the first time after an Ack is received from the remote relay. + // called for the first time after an Ack is received from the receiving gateway. // A locally created RequestState with status Pending or Error is stored. - // When a response is received from the remote relay it will write the + // When a response is received from the receiving gateway it will write the // returned RequestState with status Completed or Error. fn update_request_status( curr_request_id: String, @@ -796,7 +795,7 @@ fn spawn_send_asset_transfer_request( db_open_retry_backoff_msec: u32, state: Option, ) { - let db = Database { + let satp_db = Database { db_path: curr_db_path, db_open_max_retries: db_open_max_retries, db_open_retry_backoff_msec: db_open_retry_backoff_msec, @@ -808,14 +807,14 @@ fn spawn_send_asset_transfer_request( }; // Panic if this fails, atm the panic is just logged by the tokio runtime - db.set(&curr_request_id, &target) + satp_db.set(&curr_request_id, &target) .expect("Failed to insert into DB"); println!("Successfully written RequestState to database"); - println!("{:?}\n", db.get::(curr_request_id).unwrap()) + println!("{:?}\n", satp_db.get::(curr_request_id).unwrap()) } - // Spawning new thread to make the data_transfer_call to remote relay + // Spawning new thread to make the data_transfer_call to receiving gateway tokio::spawn(async move { - let db_path = conf.get_str("db_path").unwrap(); + let db_path = conf.get_str("satp_db_path").unwrap(); // Iterate through the relay entries in the configuration to find a match let relays_table = conf.get_table("relays").unwrap(); @@ -839,9 +838,9 @@ fn spawn_send_asset_transfer_request( relay_tlsca_cert_path.to_string(), ) .await; - println!("Received Ack from remote relay: {:?}\n", result); + println!("Received Ack from receiving gateway: {:?}\n", result); // Potentially clean up when more skilled at Rust. - // Updates the request in the DB depending on the response status from the remote relay + // Updates the request in the DB depending on the response status from the receiving gateway match result { Ok(ack_response) => { let ack_response_into_inner = ack_response.into_inner().clone(); @@ -919,16 +918,32 @@ async fn asset_transfer_call( } else { client = AssetTransferClient::connect(client_addr).await?; } + + // let asset_transfer_initialization_claim = ::core::option::Option::new(AssetTransferInitializationClaims { + // asset_asset_id: "asset_asset_id1".to_string(), + // asset_profile_id: "asset_profile_id1".to_string(), + // verified_originator_entity_id: "verified_originator_entity_id1".to_string(), + // verified_beneficiary_entity_id: "verified_beneficiary_entity_id1".to_string(), + // originator_pubkey: "originator_pubkey1".to_string(), + // beneficiary_pubkey: "beneficiary_pubkey1".to_string(), + // sender_gateway_network_id: "sender_gateway_network_id1".to_string(), + // recipient_gateway_network_id: "recipient_gateway_network_id1".to_string(), + // client_identity_pubkey: "client_identity_pubkey1".to_string(), + // server_identity_pubkey: "server_identity_pubkey1".to_string(), + // sender_gateway_owner_id: "sender_gateway_owner_id1".to_string(), + // receiver_gateway_owner_id: "receiver_gateway_owner_id1".to_string(), + // }); + let transfer_commence_request = tonic::Request::new(TransferCommenceRequest { - message_type: todo!(), - session_id: todo!(), - transfer_context_id: todo!(), - client_identity_pubkey: todo!(), - server_identity_pubkey: todo!(), - hash_transfer_init_claims: todo!(), - hash_prev_message: todo!(), - client_transfer_number: todo!(), - client_signature: todo!(), + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + hash_transfer_init_claims: "hash_transfer_init_claims1".to_string(), + hash_prev_message: "hash_prev_message1".to_string(), + client_transfer_number: "client_transfer_number1".to_string(), + client_signature: "client_signature1".to_string() }); println!("Transfer commence request: {:?}", transfer_commence_request); let response = client.transfer_commence(transfer_commence_request).await?; From bfb3d874bec41b1912b0798d3e7ead1026e8a8d1 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Fri, 30 Jun 2023 22:37:11 +0100 Subject: [PATCH 03/59] initial commit --- weaver/common/protos-rs/build.rs | 2 +- .../pkg/src/generated/networks.networks.rs | 41 +- .../pkg/src/generated/relay.asset_transfer.rs | 66 +- .../protos-rs/pkg/src/generated/relay.satp.rs | 593 ++++++++++++++++++ weaver/common/protos-rs/pkg/src/lib.rs | 4 +- weaver/common/protos/networks/networks.proto | 18 +- .../{asset_transfer.proto => satp.proto} | 4 +- weaver/core/relay/config/Corda_Relay.toml | 6 +- weaver/core/relay/config/Corda_Relay2.toml | 4 +- weaver/core/relay/config/Dummy_Relay.toml | 6 +- weaver/core/relay/config/Dummy_Relay_tls.toml | 4 +- weaver/core/relay/config/Fabric_Relay.toml | 4 +- weaver/core/relay/config/Fabric_Relay2.toml | 4 +- weaver/core/relay/config/Settings.toml | 6 +- weaver/core/relay/src/main.rs | 19 +- weaver/core/relay/src/satp_client.rs | 17 +- weaver/core/relay/src/services/mod.rs | 3 +- .../relay/src/services/network_service.rs | 346 +++++----- ...et_transfer_service.rs => satp_service.rs} | 116 ++-- 19 files changed, 929 insertions(+), 334 deletions(-) create mode 100644 weaver/common/protos-rs/pkg/src/generated/relay.satp.rs rename weaver/common/protos/relay/{asset_transfer.proto => satp.proto} (98%) rename weaver/core/relay/src/services/{asset_transfer_service.rs => satp_service.rs} (69%) diff --git a/weaver/common/protos-rs/build.rs b/weaver/common/protos-rs/build.rs index d128ff1516..58e1d86d78 100644 --- a/weaver/common/protos-rs/build.rs +++ b/weaver/common/protos-rs/build.rs @@ -7,7 +7,7 @@ fn main() -> Result<(), Box> { .compile( &[ "../protos/relay/datatransfer.proto", - "../protos/relay/asset_transfer.proto", + "../protos/relay/satp.proto", "../protos/relay/events.proto", "../protos/networks/networks.proto", "../protos/driver/driver.proto", diff --git a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs index 6fe0056008..0e556add31 100644 --- a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs +++ b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs @@ -70,6 +70,29 @@ pub struct NetworkEventUnsubscription { #[prost(string, tag = "2")] pub request_id: ::prost::alloc::string::String, } +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NetworkAssetTransfer { + #[prost(string, repeated, tag = "1")] + pub policy: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(string, tag = "2")] + pub address: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub requesting_relay: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub requesting_network: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub certificate: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub requestor_signature: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub nonce: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub requesting_org: ::prost::alloc::string::String, + #[prost(bool, tag = "9")] + pub confidential: bool, +} /// Generated client implementations. pub mod network_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] @@ -208,11 +231,11 @@ pub mod network_client { ); self.inner.unary(request.into_request(), path, codec).await } - /// Asset Transfer endpoints - /// endpoint for a network to request asset transfer to relay state via local relay + /// SATP endpoints + /// endpoint for a network to request asset transfer to a receiving gateway via local gateway pub async fn request_asset_transfer( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> Result< tonic::Response, tonic::Status, @@ -357,11 +380,11 @@ pub mod network_server { &self, request: tonic::Request, ) -> Result, tonic::Status>; - /// Asset Transfer endpoints - /// endpoint for a network to request asset transfer to relay state via local relay + /// SATP endpoints + /// endpoint for a network to request asset transfer to a receiving gateway via local gateway async fn request_asset_transfer( &self, - request: tonic::Request, + request: tonic::Request, ) -> Result< tonic::Response, tonic::Status, @@ -577,7 +600,9 @@ pub mod network_server { "/networks.networks.Network/RequestAssetTransfer" => { #[allow(non_camel_case_types)] struct RequestAssetTransferSvc(pub Arc); - impl tonic::server::UnaryService + impl< + T: Network, + > tonic::server::UnaryService for RequestAssetTransferSvc { type Response = super::super::super::common::ack::Ack; type Future = BoxFuture< @@ -586,7 +611,7 @@ pub mod network_server { >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = self.0.clone(); let fut = async move { diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs b/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs index bcf6e36f1e..9a9d8617b8 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs @@ -121,15 +121,15 @@ pub struct LockAssertionReceiptRequest { pub server_signature: ::prost::alloc::string::String, } /// Generated client implementations. -pub mod asset_transfer_client { +pub mod satp_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] use tonic::codegen::*; use tonic::codegen::http::Uri; #[derive(Debug, Clone)] - pub struct AssetTransferClient { + pub struct SatpClient { inner: tonic::client::Grpc, } - impl AssetTransferClient { + impl SatpClient { /// Attempt to create a new client by connecting to a given endpoint. pub async fn connect(dst: D) -> Result where @@ -140,7 +140,7 @@ pub mod asset_transfer_client { Ok(Self::new(conn)) } } - impl AssetTransferClient + impl SatpClient where T: tonic::client::GrpcService, T::Error: Into, @@ -158,7 +158,7 @@ pub mod asset_transfer_client { pub fn with_interceptor( inner: T, interceptor: F, - ) -> AssetTransferClient> + ) -> SatpClient> where F: tonic::service::Interceptor, T::ResponseBody: Default, @@ -172,7 +172,7 @@ pub mod asset_transfer_client { http::Request, >>::Error: Into + Send + Sync, { - AssetTransferClient::new(InterceptedService::new(inner, interceptor)) + SatpClient::new(InterceptedService::new(inner, interceptor)) } /// Compress requests with the given encoding. /// @@ -209,7 +209,7 @@ pub mod asset_transfer_client { })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/relay.asset_transfer.AssetTransfer/TransferCommence", + "/relay.asset_transfer.SATP/TransferCommence", ); self.inner.unary(request.into_request(), path, codec).await } @@ -233,7 +233,7 @@ pub mod asset_transfer_client { })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/relay.asset_transfer.AssetTransfer/CommenceResponse", + "/relay.asset_transfer.SATP/CommenceResponse", ); self.inner.unary(request.into_request(), path, codec).await } @@ -258,7 +258,7 @@ pub mod asset_transfer_client { })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/relay.asset_transfer.AssetTransfer/LockAssertion", + "/relay.asset_transfer.SATP/LockAssertion", ); self.inner.unary(request.into_request(), path, codec).await } @@ -282,19 +282,19 @@ pub mod asset_transfer_client { })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/relay.asset_transfer.AssetTransfer/LockAssertionReceipt", + "/relay.asset_transfer.SATP/LockAssertionReceipt", ); self.inner.unary(request.into_request(), path, codec).await } } } /// Generated server implementations. -pub mod asset_transfer_server { +pub mod satp_server { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with AssetTransferServer. + /// Generated trait containing gRPC methods that should be implemented for use with SatpServer. #[async_trait] - pub trait AssetTransfer: Send + Sync + 'static { + pub trait Satp: Send + Sync + 'static { /// The sender gateway sends a TransferCommence request to signal to the receiver gateway /// that the it is ready to start the transfer of the digital asset async fn transfer_commence( @@ -334,13 +334,13 @@ pub mod asset_transfer_server { >; } #[derive(Debug)] - pub struct AssetTransferServer { + pub struct SatpServer { inner: _Inner, accept_compression_encodings: EnabledCompressionEncodings, send_compression_encodings: EnabledCompressionEncodings, } struct _Inner(Arc); - impl AssetTransferServer { + impl SatpServer { pub fn new(inner: T) -> Self { Self::from_arc(Arc::new(inner)) } @@ -374,9 +374,9 @@ pub mod asset_transfer_server { self } } - impl tonic::codegen::Service> for AssetTransferServer + impl tonic::codegen::Service> for SatpServer where - T: AssetTransfer, + T: Satp, B: Body + Send + 'static, B::Error: Into + Send + 'static, { @@ -392,11 +392,11 @@ pub mod asset_transfer_server { fn call(&mut self, req: http::Request) -> Self::Future { let inner = self.inner.clone(); match req.uri().path() { - "/relay.asset_transfer.AssetTransfer/TransferCommence" => { + "/relay.asset_transfer.SATP/TransferCommence" => { #[allow(non_camel_case_types)] - struct TransferCommenceSvc(pub Arc); + struct TransferCommenceSvc(pub Arc); impl< - T: AssetTransfer, + T: Satp, > tonic::server::UnaryService for TransferCommenceSvc { type Response = super::super::super::common::ack::Ack; @@ -432,11 +432,11 @@ pub mod asset_transfer_server { }; Box::pin(fut) } - "/relay.asset_transfer.AssetTransfer/CommenceResponse" => { + "/relay.asset_transfer.SATP/CommenceResponse" => { #[allow(non_camel_case_types)] - struct CommenceResponseSvc(pub Arc); + struct CommenceResponseSvc(pub Arc); impl< - T: AssetTransfer, + T: Satp, > tonic::server::UnaryService for CommenceResponseSvc { type Response = super::super::super::common::ack::Ack; @@ -472,11 +472,11 @@ pub mod asset_transfer_server { }; Box::pin(fut) } - "/relay.asset_transfer.AssetTransfer/LockAssertion" => { + "/relay.asset_transfer.SATP/LockAssertion" => { #[allow(non_camel_case_types)] - struct LockAssertionSvc(pub Arc); + struct LockAssertionSvc(pub Arc); impl< - T: AssetTransfer, + T: Satp, > tonic::server::UnaryService for LockAssertionSvc { type Response = super::super::super::common::ack::Ack; @@ -512,11 +512,11 @@ pub mod asset_transfer_server { }; Box::pin(fut) } - "/relay.asset_transfer.AssetTransfer/LockAssertionReceipt" => { + "/relay.asset_transfer.SATP/LockAssertionReceipt" => { #[allow(non_camel_case_types)] - struct LockAssertionReceiptSvc(pub Arc); + struct LockAssertionReceiptSvc(pub Arc); impl< - T: AssetTransfer, + T: Satp, > tonic::server::UnaryService for LockAssertionReceiptSvc { type Response = super::super::super::common::ack::Ack; @@ -567,7 +567,7 @@ pub mod asset_transfer_server { } } } - impl Clone for AssetTransferServer { + impl Clone for SatpServer { fn clone(&self) -> Self { let inner = self.inner.clone(); Self { @@ -577,7 +577,7 @@ pub mod asset_transfer_server { } } } - impl Clone for _Inner { + impl Clone for _Inner { fn clone(&self) -> Self { Self(self.0.clone()) } @@ -587,7 +587,7 @@ pub mod asset_transfer_server { write!(f, "{:?}", self.0) } } - impl tonic::server::NamedService for AssetTransferServer { - const NAME: &'static str = "relay.asset_transfer.AssetTransfer"; + impl tonic::server::NamedService for SatpServer { + const NAME: &'static str = "relay.asset_transfer.SATP"; } } diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs new file mode 100644 index 0000000000..fb265aa96e --- /dev/null +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -0,0 +1,593 @@ +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AssetTransferInitializationClaims { + #[prost(string, tag = "1")] + pub asset_asset_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub asset_profile_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub verified_originator_entity_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub verified_beneficiary_entity_id: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub originator_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub beneficiary_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub sender_gateway_network_id: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub recipient_gateway_network_id: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "10")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "11")] + pub sender_gateway_owner_id: ::prost::alloc::string::String, + #[prost(string, tag = "12")] + pub receiver_gateway_owner_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransferCommenceRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub hash_transfer_init_claims: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub hash_prev_message: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub client_transfer_number: ::prost::alloc::string::String, + /// AssetTransferInitializationClaims asset_transfer_initialization_claims = 10; + #[prost(string, tag = "9")] + pub client_signature: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommenceResponseRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub hash_prev_message: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub server_transfer_number: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub server_signature: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LockAssertionRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub lock_assertion_claim: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub lock_assertion_claim_format: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub lock_assertion_expiration: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub hash_prev_message: ::prost::alloc::string::String, + #[prost(string, tag = "10")] + pub client_transfer_number: ::prost::alloc::string::String, + #[prost(string, tag = "11")] + pub client_signature: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LockAssertionReceiptRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub hash_prev_message: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub server_transfer_number: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub server_signature: ::prost::alloc::string::String, +} +/// Generated client implementations. +pub mod satp_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct SatpClient { + inner: tonic::client::Grpc, + } + impl SatpClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: std::convert::TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl SatpClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> SatpClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + SatpClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// The sender gateway sends a TransferCommence request to signal to the receiver gateway + /// that the it is ready to start the transfer of the digital asset + pub async fn transfer_commence( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/TransferCommence", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// The receiver gateway sends a CommenceResponse request to the sender gateway to indicate agreement + /// to proceed with the asset transfe + pub async fn commence_response( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/CommenceResponse", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway + /// declaring that the asset in question has been locked or escrowed by the sender gateway in + /// the origin network (e.g. to prevent double spending + pub async fn lock_assertion( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/LockAssertion", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// The receiver gateway sends a LockAssertionReceipt request to the sender gateway to indicate acceptance + /// of the claim(s) delivered by the sender gateway in the previous message + pub async fn lock_assertion_receipt( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/LockAssertionReceipt", + ); + self.inner.unary(request.into_request(), path, codec).await + } + } +} +/// Generated server implementations. +pub mod satp_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with SatpServer. + #[async_trait] + pub trait Satp: Send + Sync + 'static { + /// The sender gateway sends a TransferCommence request to signal to the receiver gateway + /// that the it is ready to start the transfer of the digital asset + async fn transfer_commence( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// The receiver gateway sends a CommenceResponse request to the sender gateway to indicate agreement + /// to proceed with the asset transfe + async fn commence_response( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway + /// declaring that the asset in question has been locked or escrowed by the sender gateway in + /// the origin network (e.g. to prevent double spending + async fn lock_assertion( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// The receiver gateway sends a LockAssertionReceipt request to the sender gateway to indicate acceptance + /// of the claim(s) delivered by the sender gateway in the previous message + async fn lock_assertion_receipt( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + } + #[derive(Debug)] + pub struct SatpServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + } + struct _Inner(Arc); + impl SatpServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + let inner = _Inner(inner); + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + } + impl tonic::codegen::Service> for SatpServer + where + T: Satp, + B: Body + Send + 'static, + B::Error: Into + Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/relay.satp.SATP/TransferCommence" => { + #[allow(non_camel_case_types)] + struct TransferCommenceSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for TransferCommenceSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).transfer_commence(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = TransferCommenceSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/CommenceResponse" => { + #[allow(non_camel_case_types)] + struct CommenceResponseSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for CommenceResponseSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).commence_response(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommenceResponseSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/LockAssertion" => { + #[allow(non_camel_case_types)] + struct LockAssertionSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for LockAssertionSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).lock_assertion(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = LockAssertionSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/LockAssertionReceipt" => { + #[allow(non_camel_case_types)] + struct LockAssertionReceiptSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for LockAssertionReceiptSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).lock_assertion_receipt(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = LockAssertionReceiptSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for SatpServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + } + } + } + impl Clone for _Inner { + fn clone(&self) -> Self { + Self(self.0.clone()) + } + } + impl std::fmt::Debug for _Inner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl tonic::server::NamedService for SatpServer { + const NAME: &'static str = "relay.satp.SATP"; + } +} diff --git a/weaver/common/protos-rs/pkg/src/lib.rs b/weaver/common/protos-rs/pkg/src/lib.rs index c77501af32..e2e07520c1 100644 --- a/weaver/common/protos-rs/pkg/src/lib.rs +++ b/weaver/common/protos-rs/pkg/src/lib.rs @@ -2,8 +2,8 @@ pub mod relay { pub mod datatransfer { include!(concat!("./generated", "/relay.datatransfer.rs")); } - pub mod asset_transfer { - include!(concat!("./generated", "/relay.asset_transfer.rs")); + pub mod satp { + include!(concat!("./generated", "/relay.satp.rs")); } pub mod events { include!(concat!("./generated", "/relay.events.rs")); diff --git a/weaver/common/protos/networks/networks.proto b/weaver/common/protos/networks/networks.proto index ab689a975a..d1b6f636e8 100644 --- a/weaver/common/protos/networks/networks.proto +++ b/weaver/common/protos/networks/networks.proto @@ -20,9 +20,9 @@ service Network { // NOTE: This rpc is just for debugging. rpc RequestDatabase(DbName) returns (RelayDatabase) {} - // Asset Transfer endpoints - // endpoint for a network to request asset transfer to relay state via local relay - rpc RequestAssetTransfer(NetworkQuery) returns (common.ack.Ack) {} + // SATP endpoints + // endpoint for a network to request asset transfer to a receiving gateway via local gateway + rpc RequestAssetTransfer(NetworkAssetTransfer) returns (common.ack.Ack) {} // Event endpoints // endpoint for a client to subscribe to event via local relay initiating subscription flow. @@ -71,3 +71,15 @@ message NetworkEventUnsubscription { NetworkEventSubscription request = 1; string request_id = 2; } + +message NetworkAssetTransfer { + repeated string policy = 1; + string address = 2; + string requesting_relay = 3; + string requesting_network = 4; + string certificate = 5; + string requestor_signature = 6; + string nonce = 7; + string requesting_org = 8; + bool confidential = 9; +} \ No newline at end of file diff --git a/weaver/common/protos/relay/asset_transfer.proto b/weaver/common/protos/relay/satp.proto similarity index 98% rename from weaver/common/protos/relay/asset_transfer.proto rename to weaver/common/protos/relay/satp.proto index dbded4b908..e4df80f997 100644 --- a/weaver/common/protos/relay/asset_transfer.proto +++ b/weaver/common/protos/relay/satp.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package relay.asset_transfer; +package relay.satp; import "common/ack.proto"; import "common/state.proto"; @@ -9,7 +9,7 @@ import "common/query.proto"; option java_package = "org.hyperledger.cacti.weaver.protos.relay.datatransfer"; option go_package = "github.com/hyperledger/cacti/weaver/common/protos-go/v2/relay"; -service AssetTransfer { +service SATP { // Stage 2 endpoints // The sender gateway sends a TransferCommence request to signal to the receiver gateway diff --git a/weaver/core/relay/config/Corda_Relay.toml b/weaver/core/relay/config/Corda_Relay.toml index 76a27993d5..08fa0b78af 100644 --- a/weaver/core/relay/config/Corda_Relay.toml +++ b/weaver/core/relay/config/Corda_Relay.toml @@ -3,10 +3,12 @@ port="9081" host="localhost" hostname="localhost" db_path="db/Corda_Relay/requests" -satp_db_path="satp_db/Corda_Relay/requests" +db_satp_requests_path="db/Corda_Relay/satp/requests" +db_satp_requests_states_path="db/Corda_Relay/satp/requests_states" # This will be replaced by the task queue. remote_db_path="db/Corda_Relay/remote_request" -remote_satp_db_path="satp_db/Corda_Relay/remote_request" +remote_db_satp_requests_path="db/Corda_Relay/satp/remote_requests_states" +remote_db_satp_requests_states_path="db/Corda_Relay/satp/requests_states" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Corda_Relay2.toml b/weaver/core/relay/config/Corda_Relay2.toml index 9912ca261c..1a53a655df 100644 --- a/weaver/core/relay/config/Corda_Relay2.toml +++ b/weaver/core/relay/config/Corda_Relay2.toml @@ -3,10 +3,10 @@ port="9082" host="localhost" hostname="localhost" db_path="db/Corda_Relay2/requests" -satp_db_path="satp_db/Corda_Relay2/requests" +db_satp_path="db/Corda_Relay2/satp/requests" # This will be replaced by the task queue. remote_db_path="db/Corda_Relay2/remote_request" -remote_satp_db_path="satp_db/Corda_Relay2/remote_request" +remote_db_satp_path="db/Corda_Relay2/satp/remote_request" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Dummy_Relay.toml b/weaver/core/relay/config/Dummy_Relay.toml index 89b194683c..48d5e858c1 100644 --- a/weaver/core/relay/config/Dummy_Relay.toml +++ b/weaver/core/relay/config/Dummy_Relay.toml @@ -2,10 +2,12 @@ name = "Dummy_Relay" port="9085" hostname="localhost" db_path="db/Dummy_Relay/requests" -satp_db_path="satp_db/Dummy_Relay/requests" +db_satp_requests_path="db/Dummy_Relay/satp/requests" +db_satp_requests_states_path="db/Dummy_Relay/satp/requests_states" # This will be replaced by the task queue. remote_db_path="db/Dummy_Relay/remote_request" -remote_satp_db_path="satp_db/Dummy_Relay/remote_request" +remote_db_satp_requests_path="db/Dummy_Relay/satp/remote_requests_states" +remote_db_satp_requests_states_path="db/Dummy_Relay/satp/requests_states" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Dummy_Relay_tls.toml b/weaver/core/relay/config/Dummy_Relay_tls.toml index b36121651c..fb466fb4e2 100644 --- a/weaver/core/relay/config/Dummy_Relay_tls.toml +++ b/weaver/core/relay/config/Dummy_Relay_tls.toml @@ -2,10 +2,10 @@ name = "Dummy_Relay" port="9085" hostname="localhost" db_path="db/Dummy_Relay_tls/requests" -satp_db_path="satp_db/Dummy_Relay_tls/requests" +db_satp_path="db/Dummy_Relay_tls/satp/requests" # This will be replaced by the task queue. remote_db_path="db/Dummy_Relay_tls/remote_request" -remote_satp_db_path="satp_db/Dummy_Relay_tls/remote_request" +remote_db_satp_path="db/Dummy_Relay_tls/satp/remote_request" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Fabric_Relay.toml b/weaver/core/relay/config/Fabric_Relay.toml index 82d513bf94..b6c36790c6 100644 --- a/weaver/core/relay/config/Fabric_Relay.toml +++ b/weaver/core/relay/config/Fabric_Relay.toml @@ -2,10 +2,10 @@ name = "Fabric_Relay" port="9080" hostname="localhost" db_path="db/Fabric_Relay/requests" -satp_db_path="satp_db/Fabric_Relay/requests" +db_satp_path="db/Fabric_Relay/satp/requests" # This will be replaced by the task queue. remote_db_path="db/Fabric_Relay/remote_request" -remote_satp_db_path="satp_db/Fabric_Relay/remote_request" +remote_db_satp_path="db/Fabric_Relay/satp/remote_request" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Fabric_Relay2.toml b/weaver/core/relay/config/Fabric_Relay2.toml index 86debc7b7a..bdb5528478 100644 --- a/weaver/core/relay/config/Fabric_Relay2.toml +++ b/weaver/core/relay/config/Fabric_Relay2.toml @@ -2,10 +2,10 @@ name = "Fabric_Relay2" port="9083" hostname="localhost" db_path="db/Fabric_Relay2/requests" -satp_db_path="satp_db/Fabric_Relay2/requests" +db_satp_path="db/Fabric_Relay2/satp/requests" # This will be replaced by the task queue. remote_db_path="db/Fabric_Relay2/remote_request" -remote_satp_db_path="satp_db/Fabric_Relay2/remote_request" +remote_db_satp_path="db/Fabric_Relay2/satp/remote_request" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Settings.toml b/weaver/core/relay/config/Settings.toml index c303ed3b4f..23185d8e6d 100644 --- a/weaver/core/relay/config/Settings.toml +++ b/weaver/core/relay/config/Settings.toml @@ -2,10 +2,12 @@ name = "Fabric_Relay" port="9080" hostname="localhost" db_path="db/requests" -satp_db_path="satp_db/requests" +db_satp_requests_path="db/satp/requests" +db_satp_requests_states_path="db/satp/requests_states" # This will be replaced by the task queue. remote_db_path="db/remote_requests" -remote_satp_db_path="satp_db/remote_requests" +remote_db_satp_requests_path="db/satp/remote_requests_states" +remote_db_satp_requests_states_path="db/satp/requests_states" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/src/main.rs b/weaver/core/relay/src/main.rs index 2efbe46b02..bbd0bdac2e 100644 --- a/weaver/core/relay/src/main.rs +++ b/weaver/core/relay/src/main.rs @@ -1,15 +1,14 @@ // Internal generated modules use weaverpb::networks::networks::network_server::NetworkServer; -use weaverpb::relay::asset_transfer::asset_transfer_server::AssetTransferServer; use weaverpb::relay::datatransfer::data_transfer_server::DataTransferServer; -use weaverpb::relay::events::event_subscribe_server::EventSubscribeServer; use weaverpb::relay::events::event_publish_server::EventPublishServer; +use weaverpb::relay::events::event_subscribe_server::EventSubscribeServer; +use weaverpb::relay::satp::satp_server::SatpServer; // Internal modules use services::data_transfer_service::DataTransferService; -use services::asset_transfer_service::AssetTransferService; -use services::event_subscribe_service::EventSubscribeService; use services::event_publish_service::EventPublishService; +use services::event_subscribe_service::EventSubscribeService; use services::network_service::NetworkService; // External modules @@ -20,6 +19,8 @@ use std::net::ToSocketAddrs; use tokio::sync::RwLock; use tonic::transport::{Identity, Server, ServerTlsConfig}; +use crate::services::satp_service::SatpService; + mod db; mod error; mod relay_proto; @@ -44,7 +45,9 @@ async fn main() -> Result<(), Box> { let relay_name = settings.get_str("name").expect("No Relay name provided"); println!("Relay Name: {:?}", relay_name); let relay_port = settings.get_str("port").expect(&format!("Port does not exist for relay name {}. Make sure the config file <{}> has the name and port specified.", relay_name, config_file_name.to_string())); - let host = settings.get_str("hostname").unwrap_or("localhost".to_string()); + let host = settings + .get_str("hostname") + .unwrap_or("localhost".to_string()); let with_tls = settings.get_bool("tls").unwrap_or(false); // Converts port to a valid socket address @@ -56,7 +59,7 @@ async fn main() -> Result<(), Box> { let relay = DataTransferService { config_lock: RwLock::new(settings.clone()), }; - let gateway = AssetTransferService { + let gateway = SatpService { config_lock: RwLock::new(settings.clone()), }; let event_subscribe = EventSubscribeService { @@ -78,7 +81,7 @@ async fn main() -> Result<(), Box> { let server = Server::builder() .tls_config(ServerTlsConfig::new().identity(identity))? .add_service(DataTransferServer::new(relay)) - .add_service(AssetTransferServer::new(gateway)) + .add_service(SatpServer::new(gateway)) .add_service(EventSubscribeServer::new(event_subscribe)) .add_service(EventPublishServer::new(event_publish)) .add_service(NetworkServer::new(network)); @@ -87,7 +90,7 @@ async fn main() -> Result<(), Box> { // Spins up two gRPC services in a tonic server. One for relay to relay and one for network to relay communication. let server = Server::builder() .add_service(DataTransferServer::new(relay)) - .add_service(AssetTransferServer::new(gateway)) + .add_service(SatpServer::new(gateway)) .add_service(EventSubscribeServer::new(event_subscribe)) .add_service(EventPublishServer::new(event_publish)) .add_service(NetworkServer::new(network)); diff --git a/weaver/core/relay/src/satp_client.rs b/weaver/core/relay/src/satp_client.rs index dcf99d21d4..84bedb7f2c 100644 --- a/weaver/core/relay/src/satp_client.rs +++ b/weaver/core/relay/src/satp_client.rs @@ -1,15 +1,8 @@ mod relay_proto; -use futures::future::{BoxFuture, FutureExt}; -use weaverpb::common::ack::ack; -use weaverpb::common::state::{request_state, view_payload, ViewPayload, View, Meta, meta}; -use weaverpb::common::events::{event_subscription_state, EventMatcher, EventPublication, event_publication, ContractTransaction}; -use weaverpb::relay::events::{event_publish_client::EventPublishClient}; -use weaverpb::networks::networks::{network_client::NetworkClient, GetStateMessage, NetworkQuery, NetworkEventSubscription, NetworkEventUnsubscription}; use relay_proto::get_url; use std::env; -use std::thread::sleep; -use std::time; -use serde_json; +use weaverpb::common::ack::ack; +use weaverpb::networks::networks::{network_client::NetworkClient, NetworkAssetTransfer}; #[tokio::main] async fn main() -> Result<(), Box> { @@ -25,10 +18,10 @@ async fn asset_transfer() -> Result<(), Box> { // localhost:9081/Corda_Network/test // {locationsegment}/{Network_id}/{query} // localhost:9081/Corda_Network/mychannel:simplestate:read:TestState - let request = tonic::Request::new(NetworkQuery { + let request = tonic::Request::new(NetworkAssetTransfer { policy: vec!["test".to_string()], address: args[2].to_string(), - requesting_relay: "".to_string(), + requesting_relay: "Dummy_relay".to_string(), requesting_network: "".to_string(), requesting_org: "".to_string(), certificate: "test".to_string(), @@ -42,7 +35,7 @@ async fn asset_transfer() -> Result<(), Box> { match ack::Status::from_i32(response.get_ref().status) { Some(ack_status) => match ack_status { ack::Status::Ok => { - //poll_for_asset_state(request_id.to_string(), network_client, 0).await; + // TODO poll for asset transfer status println!("Asset Transfer: Success!"); } ack::Status::Error => { diff --git a/weaver/core/relay/src/services/mod.rs b/weaver/core/relay/src/services/mod.rs index 327e85b08e..98d370570c 100644 --- a/weaver/core/relay/src/services/mod.rs +++ b/weaver/core/relay/src/services/mod.rs @@ -1,7 +1,8 @@ pub mod data_transfer_service; -pub mod asset_transfer_service; +pub mod satp_service; pub mod network_service; pub mod event_subscribe_service; pub mod event_publish_service; pub mod helpers; +pub mod satp_helper; pub mod types; diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 54675e3fb8..4d15987ae6 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -1,21 +1,24 @@ +use std::error::Error; + // Internal generated modules use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::query::Query; use weaverpb::common::state::{request_state, RequestState}; use weaverpb::common::events::{EventSubscription, event_subscription_state, EventSubscriptionState, EventSubOperation, event_publication, EventPublication, EventStates}; use weaverpb::networks::networks::network_server::Network; -use weaverpb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription, NetworkEventUnsubscription}; -use weaverpb::relay::asset_transfer::{TransferCommenceRequest, AssetTransferInitializationClaims}; +use weaverpb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription, NetworkEventUnsubscription, NetworkAssetTransfer}; +use weaverpb::relay::satp::{TransferCommenceRequest}; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; -use weaverpb::relay::asset_transfer::asset_transfer_client::AssetTransferClient; +use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::relay_proto::{parse_address, LocationSegment}; // Internal modules use crate::db::Database; use crate::services::helpers::{update_event_subscription_status, driver_sign_subscription_helper, try_mark_request_state_deleted, mark_event_states_deleted, delete_event_pub_spec, get_event_publication_key, get_event_subscription_key}; +use crate::services::satp_helper::{derive_transfer_commence_request, log_request_state_in_local_sapt_db, log_request_in_local_sapt_db, update_request_state_in_local_satp_db}; // External modules -use config; +use config::{self, Config}; use sled::open; use tokio::sync::RwLock; use tonic::{Code, Request, Response, Status}; @@ -196,87 +199,6 @@ impl Network for NetworkService { } } - /// request_asset_transfer is called from the client to query the sending gateway to transfer an asset. - /// the request info/state machine is stored in a db on the sending gateway - async fn request_asset_transfer(&self, request: Request) -> Result, Status> { - println!( - "Got a NetworkQuery request from {:?} - {:?}", - request.remote_addr(), - request - ); - let conf = self.config_lock.read().await.clone(); - // Database access/storage - let satp_db = Database { - db_path: conf.get_str("satp_db_path").unwrap(), - db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, - }; - - let request_id = Uuid::new_v4(); - // Initial request state stored in DB. - let target: RequestState = RequestState { - status: request_state::Status::PendingAck as i32, - request_id: request_id.to_string(), - state: None, - }; - let message_insert = satp_db.set(&request_id.to_string(), &target); - // Kept this as a match as the error case returns an Ok. - match message_insert { - Ok(_) => println!( - "Successfully stored NetworkQuery in satp_db with request_id: {}", - request_id.to_string() - ), - Err(e) => { - // Internal failure of sled. Send Error response - println!( - "Error storing NetworkQuery in satp_db for request_id: {}", - request_id.to_string() - ); - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error storing NetworkQuery in satp_db {:?}", e), - })); - println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); - return reply; - } - } - - let network_query = request.into_inner().clone(); - let parsed_address = parse_address(network_query.address.to_string()); - match parsed_address { - Ok(address) => { - // TODO: verify that host and port are valid - // Spawns a child process to handle sending request - spawn_send_asset_transfer_request( - conf, - network_query, - request_id.to_string(), - address.location.hostname.to_string(), - address.location.port.to_string() - ); - // Send Ack back to network while request is happening in a thread - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request_id.to_string(), - message: "".to_string(), - }; - println!("Sending Ack of the asset transfer request back to network: {:?}\n", reply); - Ok(Response::new(reply)) - } - Err(e) => { - println!("Invalid Address"); - let reply = Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error: {:?}", e), - }; - println!("Sending Ack back with an error to network: {:?}\n", reply); - Ok(Response::new(reply)) - } - } - } - // Subscribe Event Endpoints async fn subscribe_event(&self, request: Request) -> Result, Status> { println!( @@ -492,6 +414,104 @@ impl Network for NetworkService { )), } } + + /// request_asset_transfer is called from the client to query the sending gateway to transfer an asset. + /// The request info/state machine is stored in a db on the sending gateway + async fn request_asset_transfer(&self, request: Request) -> Result, Status> { + println!( + "Got a NetworkAssetTransfer request from {:?} - {:?}", + request.remote_addr(), + request + ); + let conf = self.config_lock.read().await.clone(); + let network_asset_transfer = request.into_inner().clone(); + // TODO: request_id should be the hash of network_asset_transfer + let request_id = network_asset_transfer.requesting_relay.to_string(); + // TODO refactor + let request_logged: Result, crate::error::Error> = log_request_in_local_sapt_db(&request_id, &network_asset_transfer, conf.clone()); + match request_logged { + Ok(_) => println!( + "Successfully stored NetworkAssetTransfer in local satp_db with request_id: {}", + request_id + ), + Err(e) => { + // Internal failure of sled. Send Error response + println!( + "Error storing NetworkAssetTransfer in local satp_db for request_id: {}", + request_id + ); + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: request_id, + message: format!("Error storing NetworkAssetTransfer in local satp_db {:?}", e), + })); + println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); + return reply; + } + } + + // Initial request state stored in DB. + let target: RequestState = RequestState { + status: request_state::Status::PendingAck as i32, + request_id: request_id.clone(), + state: None, + }; + let request_state_logged: Result, crate::error::Error> = log_request_state_in_local_sapt_db(&request_id, &target, conf.clone()); + match request_state_logged { + Ok(_) => println!( + "Successfully stored RequestState in local satp_db with request_id: {}", + request_id + ), + Err(e) => { + // Internal failure of sled. Send Error response + println!( + "Error storing RequestState in local satp_db for request_id: {}", + request_id + ); + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: request_id, + message: format!("Error storing RequestState in local satp_db {:?}", e), + })); + println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); + return reply; + } + } + + let transfer_commence_request: TransferCommenceRequest = derive_transfer_commence_request(network_asset_transfer.clone()); + let parsed_address = parse_address(network_asset_transfer.address.to_string()); + match parsed_address { + Ok(address) => { + // TODO: verify that host and port are valid + // Spawns a child process to handle sending request + spawn_send_asset_transfer_request( + conf, + transfer_commence_request, + address.location.hostname.to_string(), + address.location.port.to_string() + ); + // Send Ack back to network while request is happening in a thread + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id, + message: "".to_string(), + }; + println!("Sending Ack of the asset transfer request back to network: {:?}\n", reply); + Ok(Response::new(reply)) + } + Err(e) => { + println!("Invalid Address"); + let reply = Ack { + status: ack::Status::Error as i32, + request_id: request_id, + message: format!("Error: {:?}", e), + }; + println!("Sending Ack back with an error to network: {:?}\n", reply); + Ok(Response::new(reply)) + } + } + } + } async fn event_subscription_helper( @@ -776,8 +796,7 @@ async fn data_transfer_call( // Sends a request to the receiving gateway fn spawn_send_asset_transfer_request( conf: config::Config, - network_query: NetworkQuery, - request_id: String, + transfer_commence_request: TransferCommenceRequest, relay_host: String, relay_port: String, ) { @@ -787,35 +806,9 @@ fn spawn_send_asset_transfer_request( // A locally created RequestState with status Pending or Error is stored. // When a response is received from the receiving gateway it will write the // returned RequestState with status Completed or Error. - fn update_request_status( - curr_request_id: String, - new_status: request_state::Status, - curr_db_path: String, - db_open_max_retries: u32, - db_open_retry_backoff_msec: u32, - state: Option, - ) { - let satp_db = Database { - db_path: curr_db_path, - db_open_max_retries: db_open_max_retries, - db_open_retry_backoff_msec: db_open_retry_backoff_msec, - }; - let target: RequestState = RequestState { - status: new_status as i32, - request_id: curr_request_id.clone(), - state, - }; - // Panic if this fails, atm the panic is just logged by the tokio runtime - satp_db.set(&curr_request_id, &target) - .expect("Failed to insert into DB"); - println!("Successfully written RequestState to database"); - println!("{:?}\n", satp_db.get::(curr_request_id).unwrap()) - } // Spawning new thread to make the data_transfer_call to receiving gateway tokio::spawn(async move { - let db_path = conf.get_str("satp_db_path").unwrap(); - // Iterate through the relay entries in the configuration to find a match let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; @@ -828,79 +821,70 @@ fn spawn_send_asset_transfer_request( } } + let request_id = transfer_commence_request.session_id.to_string(); let result = asset_transfer_call( - conf.get_str("name").unwrap(), relay_host, relay_port, - network_query, - request_id.clone(), + transfer_commence_request, relay_tls, relay_tlsca_cert_path.to_string(), ) .await; println!("Received Ack from receiving gateway: {:?}\n", result); - // Potentially clean up when more skilled at Rust. // Updates the request in the DB depending on the response status from the receiving gateway - match result { - Ok(ack_response) => { - let ack_response_into_inner = ack_response.into_inner().clone(); - // This match first checks if the status is valid. - match ack::Status::from_i32(ack_response_into_inner.status) { - Some(status) => match status { - ack::Status::Ok => update_request_status( - request_id.to_string(), - request_state::Status::Pending, - db_path.to_string(), - conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, - None, - ), - ack::Status::Error => update_request_status( - request_id.to_string(), - request_state::Status::Error, - db_path.to_string(), - conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, - Some(request_state::State::Error( - ack_response_into_inner.message.to_string(), - )), - ), - }, - None => update_request_status( - request_id.to_string(), - request_state::Status::Error, - db_path.to_string(), - conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + log_result(&request_id, result, conf); + }); +} + +fn log_result(request_id: &String, result: Result, Box>, conf: Config) { + match result { + Ok(ack_response) => { + let ack_response_into_inner = ack_response.into_inner().clone(); + // This match first checks if the status is valid. + match ack::Status::from_i32(ack_response_into_inner.status) { + Some(status) => match status { + ack::Status::Ok => update_request_state_in_local_satp_db( + request_id.to_string(), + request_state::Status::Pending, + None, + conf) + , + ack::Status::Error => update_request_state_in_local_satp_db( + request_id.to_string(), + request_state::Status::Error, Some(request_state::State::Error( - "Status is not supported or is invalid".to_string(), - )), - ), - } + ack_response_into_inner.message.to_string(), + )), + conf) + , + }, + None => update_request_state_in_local_satp_db( + request_id.to_string(), + request_state::Status::Error, + Some(request_state::State::Error( + "Status is not supported or is invalid".to_string(), + )), + conf) } - Err(result_error) => update_request_status( - request_id.to_string(), - request_state::Status::Error, - db_path.to_string(), - conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, - Some(request_state::State::Error(format!("{:?}", result_error))), - ), } - }); + Err(result_error) => update_request_state_in_local_satp_db( + request_id.to_string(), + request_state::Status::Error, + Some(request_state::State::Error(format!("{:?}", result_error))), + conf) + } + } // Call to remote relay for the data transfer protocol. async fn asset_transfer_call( - relay_name: String, relay_host: String, relay_port: String, - network_query: NetworkQuery, - request_id: String, + transfer_commence_request: TransferCommenceRequest, use_tls: bool, tlsca_cert_path: String, ) -> Result, Box> { let client_addr = format!("http://{}:{}", relay_host, relay_port); - let mut client; + let mut satp_client; if use_tls { let pem = tokio::fs::read(tlsca_cert_path).await?; let ca = Certificate::from_pem(pem); @@ -914,39 +898,13 @@ async fn asset_transfer_call( .connect() .await?; - client = AssetTransferClient::new(channel); + satp_client = SatpClient::new(channel); } else { - client = AssetTransferClient::connect(client_addr).await?; + satp_client = SatpClient::connect(client_addr).await?; } - // let asset_transfer_initialization_claim = ::core::option::Option::new(AssetTransferInitializationClaims { - // asset_asset_id: "asset_asset_id1".to_string(), - // asset_profile_id: "asset_profile_id1".to_string(), - // verified_originator_entity_id: "verified_originator_entity_id1".to_string(), - // verified_beneficiary_entity_id: "verified_beneficiary_entity_id1".to_string(), - // originator_pubkey: "originator_pubkey1".to_string(), - // beneficiary_pubkey: "beneficiary_pubkey1".to_string(), - // sender_gateway_network_id: "sender_gateway_network_id1".to_string(), - // recipient_gateway_network_id: "recipient_gateway_network_id1".to_string(), - // client_identity_pubkey: "client_identity_pubkey1".to_string(), - // server_identity_pubkey: "server_identity_pubkey1".to_string(), - // sender_gateway_owner_id: "sender_gateway_owner_id1".to_string(), - // receiver_gateway_owner_id: "receiver_gateway_owner_id1".to_string(), - // }); - - let transfer_commence_request = tonic::Request::new(TransferCommenceRequest { - message_type: "message_type1".to_string(), - session_id: "session_id1".to_string(), - transfer_context_id: "transfer_context_id1".to_string(), - client_identity_pubkey: "client_identity_pubkey1".to_string(), - server_identity_pubkey: "server_identity_pubkey1".to_string(), - hash_transfer_init_claims: "hash_transfer_init_claims1".to_string(), - hash_prev_message: "hash_prev_message1".to_string(), - client_transfer_number: "client_transfer_number1".to_string(), - client_signature: "client_signature1".to_string() - }); println!("Transfer commence request: {:?}", transfer_commence_request); - let response = client.transfer_commence(transfer_commence_request).await?; + let response = satp_client.transfer_commence(transfer_commence_request).await?; Ok(response) } diff --git a/weaver/core/relay/src/services/asset_transfer_service.rs b/weaver/core/relay/src/services/satp_service.rs similarity index 69% rename from weaver/core/relay/src/services/asset_transfer_service.rs rename to weaver/core/relay/src/services/satp_service.rs index 88bc26781d..60f59e1c40 100644 --- a/weaver/core/relay/src/services/asset_transfer_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,13 +1,15 @@ // Internal generated modules use weaverpb::common::ack::{ack, Ack}; -use weaverpb::relay::asset_transfer::asset_transfer_client::AssetTransferClient; -use weaverpb::relay::asset_transfer::asset_transfer_server::AssetTransfer; -use weaverpb::relay::asset_transfer::{TransferCommenceRequest, CommenceResponseRequest, LockAssertionRequest, LockAssertionReceiptRequest}; +use weaverpb::common::query::Query; +use weaverpb::relay::satp::satp_client::SatpClient; +use weaverpb::relay::satp::satp_server::Satp; +use weaverpb::relay::satp::{TransferCommenceRequest, CommenceResponseRequest, LockAssertionRequest, LockAssertionReceiptRequest}; // Internal modules use crate::db::Database; use crate::error::Error; use crate::relay_proto::{LocationSegment}; +use crate::services::satp_helper::log_request_in_remote_sapt_db; // external modules use config; @@ -16,15 +18,17 @@ use tonic::{Request, Response, Status}; use tonic::transport::{Certificate, Channel, ClientTlsConfig}; +use super::satp_helper::create_commence_response_request; + #[derive(Debug, Default)] -pub struct AssetTransferService { +pub struct SatpService { pub config_lock: RwLock, } /// AssetTransferService is the gRPC server implementation that handles the logic for /// communication of the asset transfer protocol SATP between two gateways. #[tonic::async_trait] -impl AssetTransfer for AssetTransferService { +impl Satp for SatpService { /// transfer_commence is run on the receiver gateway to allow the sender gateway to signal to the /// receiver gateway that it is ready to start the transfer of the digital asset async fn transfer_commence( @@ -32,26 +36,46 @@ impl AssetTransfer for AssetTransferService { request: Request ) -> Result, Status> { println!( - "Got a transfer commence request from {:?} - {:?}", + "Got a TransferCommenceRequest from {:?} - {:?}", request.remote_addr(), request ); let transfer_commence_request = request.into_inner().clone(); + let request_id = transfer_commence_request.session_id.to_string(); let conf = self.config_lock.read().await; - // Database access/storage - let remote_satp_db = Database { - db_path: conf.get_str("satp_db_path").unwrap(), - db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf - .get_int("db_open_retry_backoff_msec") - .unwrap_or(10) as u32, - }; - // TODO replace the session_id with request_id - let request_id = transfer_commence_request.session_id.to_string(); + let request_logged: Result, crate::error::Error> = log_request_in_remote_sapt_db(&request_id, &transfer_commence_request, conf.clone()); + match request_logged { + Ok(_) => println!( + "Successfully stored TransferCommenceRequest in local satp_db with request_id: {}", + request_id + ), + Err(e) => { + // Internal failure of sled. Send Error response + println!( + "Error storing TransferCommenceRequest in local satp_db for request_id: {}", + request_id + ); + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: request_id, + message: format!("Error storing TransferCommenceRequest in local satp_db {:?}", e), + })); + println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); + return reply; + } + } - match transfer_commence_helper(remote_satp_db, &request_id, transfer_commence_request, conf.clone()) { + // // Database access/storage + // let remote_satp_db = Database { + // db_path: conf.get_str("db_satp_path").unwrap(), + // db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, + // db_open_retry_backoff_msec: conf + // .get_int("db_open_retry_backoff_msec") + // .unwrap_or(10) as u32, + // }; + match transfer_commence_helper(transfer_commence_request, conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!("Sending Ack of transfer commence request back: {:?}\n", reply); @@ -135,24 +159,19 @@ impl AssetTransfer for AssetTransferService { } } -/// transfer_commence_helper is run on the receiving gateway to initiate asset transfer protocol that was -/// requested from the requesting gateway +/// transfer_commence_helper is run on the receiver gateway to initiate asset transfer protocol that was +/// requested from the sender gateway pub fn transfer_commence_helper( - remote_satp_db: Database, - request_id: &String, transfer_commence_request: TransferCommenceRequest, conf: config::Config ) -> Result { - let _set_query = remote_satp_db - .set(&request_id.to_string(), &transfer_commence_request) - .map_err(|e| Error::Simple(format!("DB Failure: {:?}", e)))?; - + let request_id = transfer_commence_request.session_id.to_string(); let is_valid_request = check_transfer_commence_request(transfer_commence_request.clone()); if is_valid_request { println!("The transfer commence request is valid\n"); - match send_commence_response_helper(&request_id, remote_satp_db, conf) { + match send_commence_response_helper(&request_id, conf) { Ok(ack) => { println!("Ack transfer commence request."); let reply = Ok(ack); @@ -168,7 +187,6 @@ pub fn transfer_commence_helper( }); } } - } else { println!("The transfer commence request is invalid\n"); return Ok(Ack { @@ -181,32 +199,17 @@ pub fn transfer_commence_helper( fn send_commence_response_helper( request_id: &String, - remote_satp_db: Database, conf: config::Config ) -> Result { - let transfer_commence_request: TransferCommenceRequest = remote_satp_db - .get::(request_id.to_string()) - .map_err(|e| Error::GetQuery(format!("Failed to get transfer commence request from db. Error: {:?}", e)))?; + let query: Query = remote_satp_db + .get::(request_id.to_string()) + .map_err(|e| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", e)))?; let relays_table = conf.get_table("relays")?; - // let relay_uri = relays_table - // .get(&transfer_commence_request.requesting_relay.to_string()) - // .ok_or(Error::Simple("Relay name not found".to_string()))?; - // TODO: let relay_uri = relays_table - .get(&"Dummy_Relay".to_string()) + .get(&query.requesting_relay.to_string()) .ok_or(Error::Simple("Relay name not found".to_string()))?; let uri = relay_uri.clone().try_into::()?; - - let commence_response_request = CommenceResponseRequest { - message_type: "message_type1".to_string(), - session_id: "session_id1".to_string(), - transfer_context_id: "transfer_context_id1".to_string(), - client_identity_pubkey: "client_identity_pubkey1".to_string(), - server_identity_pubkey: "server_identity_pubkey1".to_string(), - hash_prev_message: "hash_prev_message1".to_string(), - server_transfer_number: "server_transfer_number1".to_string(), - server_signature: "server_signature1".to_string(), - }; + let commence_response_request = create_commence_response_request(); spawn_send_commence_response( commence_response_request, @@ -231,7 +234,7 @@ fn spawn_send_commence_response(commence_response_request: CommenceResponseReque // view_payload::State::View(v) => println!("View Meta: {:?}, View Data: {:?}", v.meta, base64::encode(&v.data)), // view_payload::State::Error(e) => println!("Error: {:?}", e), // } - let client_addr = format!("http://{}:{}", requestor_host, requester_port); + let satp_client_addr = format!("http://{}:{}", requestor_host, requester_port); if use_tls { let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); let ca = Certificate::from_pem(pem); @@ -240,20 +243,20 @@ fn spawn_send_commence_response(commence_response_request: CommenceResponseReque .ca_certificate(ca) .domain_name(requestor_host); - let channel = Channel::from_shared(client_addr.to_string()).unwrap() - .tls_config(tls).expect(&format!("Error in TLS configuration for client: {}", client_addr.to_string())) + let channel = Channel::from_shared(satp_client_addr.to_string()).unwrap() + .tls_config(tls).expect(&format!("Error in TLS configuration for client: {}", satp_client_addr.to_string())) .connect() .await .unwrap(); - let mut client_result = AssetTransferClient::new(channel); - let response = client_result.commence_response(commence_response_request).await; + let mut satp_client_result = SatpClient::new(channel); + let response = satp_client_result.commence_response(commence_response_request).await; println!("Response ACK from sending gateway={:?}\n", response); } else { - let client_result = AssetTransferClient::connect(client_addr).await; - match client_result { - Ok(client) => { - let response = client.clone().commence_response(commence_response_request).await; + let satp_client_result = SatpClient::connect(satp_client_addr).await; + match satp_client_result { + Ok(satp_client) => { + let response = satp_client.clone().commence_response(commence_response_request).await; println!("Response ACK from sending gateway={:?}\n", response); // Not returning anything here } @@ -273,5 +276,6 @@ fn spawn_send_commence_response(commence_response_request: CommenceResponseReque } fn check_transfer_commence_request(transfer_commence_request: TransferCommenceRequest) -> bool { + //TODO true } \ No newline at end of file From 6332243ac2ebe0106e1f1ab21767d37f80050226 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Fri, 30 Jun 2023 23:10:59 +0100 Subject: [PATCH 04/59] initial commit --- weaver/core/relay/src/services/satp_helper.rs | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 weaver/core/relay/src/services/satp_helper.rs diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs new file mode 100644 index 0000000000..592f5f4868 --- /dev/null +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -0,0 +1,111 @@ +use config::Config; +use serde::{Serialize, Deserialize}; +use sled::IVec; +use weaverpb::common::state::{RequestState, request_state}; +use weaverpb::networks::networks::{NetworkAssetTransfer}; +use weaverpb::relay::satp::{TransferCommenceRequest, CommenceResponseRequest}; + +use crate::db::Database; +use crate::error; + +pub fn derive_transfer_commence_request(network_asset_transfer: NetworkAssetTransfer) -> TransferCommenceRequest { + let session_id = "to_be_calculated_session_id"; + let transfer_commence_request = TransferCommenceRequest { + message_type: "message_type1".to_string(), + session_id: session_id.to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + hash_transfer_init_claims: "hash_transfer_init_claims1".to_string(), + hash_prev_message: "hash_prev_message1".to_string(), + client_transfer_number: "client_transfer_number1".to_string(), + client_signature: "client_signature1".to_string() + }; + + return transfer_commence_request; +} + +pub fn create_commence_response_request() -> CommenceResponseRequest { + let commence_response_request = CommenceResponseRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + hash_prev_message: "hash_prev_message1".to_string(), + server_transfer_number: "server_transfer_number1".to_string(), + server_signature: "server_signature1".to_string(), + }; + + return commence_response_request; +} + +pub fn get_satp_requests_local_db(conf: Config) -> Database { + let db = Database { + db_path: conf.get_str("db_satp_requests_path").unwrap(), + db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, + db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + }; + return db; +} + +pub fn get_satp_requests_states_local_db(conf: Config) -> Database { + let db = Database { + db_path: conf.get_str("db_satp_requests_states_path").unwrap(), + db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, + db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + }; + return db; +} + +pub fn get_satp_requests_remote_db(conf: Config) -> Database { + let db = Database { + db_path: conf.get_str("remote_db_satp_requests_path").unwrap(), + db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, + db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + }; + return db; +} + +pub fn get_satp_requests_states_remote_db(conf: Config) -> Database { + let db = Database { + db_path: conf.get_str("remote_db_satp_requests_states_path").unwrap(), + db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, + db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + }; + return db; +} + +pub fn log_request_state_in_local_sapt_db(request_id: &String, target: &RequestState, conf: Config) -> Result, error::Error>{ + let db = get_satp_requests_states_local_db(conf); + return db.set(&request_id, &target); +} + +pub fn log_request_in_local_sapt_db(request_id: &String, value: T, conf: Config) -> Result, error::Error>{ + let db = get_satp_requests_local_db(conf); + return db.set(&request_id, &value); +} + +pub fn log_request_in_remote_sapt_db(request_id: &String, value: T, conf: Config) -> Result, error::Error>{ + let db = get_satp_requests_remote_db(conf); + return db.set(&request_id, &value); +} + +pub fn get_request_from_remote_sapt_db<'a, T: Deserialize<'a>>(request_id: &String, conf: Config) -> T { + let db = get_satp_requests_remote_db(conf); + let query: T = db.get::(request_id.to_string()) + .map_err(|e| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", e)))?; +} + +pub fn update_request_state_in_local_satp_db(request_id: String, new_status: request_state::Status, state: Option, conf: Config) { + let db = get_satp_requests_states_local_db(conf); + let target: RequestState = RequestState { + status: new_status as i32, + request_id: request_id.clone(), + state, + }; + db.set(&request_id, &target) + .expect("Failed to insert into DB"); + println!("Successfully written RequestState to database"); + println!("{:?}\n", db.get::(request_id).unwrap()) +} From ff66175d698b215049d5bf7c77faf8d2fd076b53 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Sat, 1 Jul 2023 12:43:18 +0100 Subject: [PATCH 05/59] initial commit --- weaver/core/relay/Cargo.toml | 5 ++ .../relay/src/services/network_service.rs | 46 ++------------ weaver/core/relay/src/services/satp_helper.rs | 61 ++++++++++++++++-- .../core/relay/src/services/satp_service.rs | 63 ++++++++++++++----- 4 files changed, 112 insertions(+), 63 deletions(-) diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index 69102fe27b..8b3f812a97 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -11,6 +11,11 @@ path = "src/main.rs" [[bin]] name = "client" path = "src/client.rs" + +[[bin]] +name = "satp_client" +path = "src/satp_client.rs" + [[bin]] name = "client-tls" path = "src/client_tls.rs" diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 4d15987ae6..9bb6fdf511 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -1,5 +1,6 @@ use std::error::Error; +use futures::TryFutureExt; // Internal generated modules use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::query::Query; @@ -15,7 +16,7 @@ use crate::relay_proto::{parse_address, LocationSegment}; // Internal modules use crate::db::Database; use crate::services::helpers::{update_event_subscription_status, driver_sign_subscription_helper, try_mark_request_state_deleted, mark_event_states_deleted, delete_event_pub_spec, get_event_publication_key, get_event_subscription_key}; -use crate::services::satp_helper::{derive_transfer_commence_request, log_request_state_in_local_sapt_db, log_request_in_local_sapt_db, update_request_state_in_local_satp_db}; +use crate::services::satp_helper::{derive_transfer_commence_request, log_request_state_in_local_sapt_db, log_request_in_local_sapt_db, update_request_state_in_local_satp_db, get_relay_params, create_satp_client}; // External modules use config::{self, Config}; @@ -801,26 +802,9 @@ fn spawn_send_asset_transfer_request( relay_port: String, ) { println!("Sending asset transfer request to receiving gateway: {:?}:{:?}", relay_host, relay_port); - // Locally scoped function to update request status in db. This function is - // called for the first time after an Ack is received from the receiving gateway. - // A locally created RequestState with status Pending or Error is stored. - // When a response is received from the receiving gateway it will write the - // returned RequestState with status Completed or Error. - // Spawning new thread to make the data_transfer_call to receiving gateway tokio::spawn(async move { - // Iterate through the relay entries in the configuration to find a match - let relays_table = conf.get_table("relays").unwrap(); - let mut relay_tls = false; - let mut relay_tlsca_cert_path = "".to_string(); - for (_relay_name, relay_spec) in relays_table { - let relay_uri = relay_spec.clone().try_into::().unwrap(); - if relay_host == relay_uri.hostname && relay_port == relay_uri.port { - relay_tls = relay_uri.tls; - relay_tlsca_cert_path = relay_uri.tlsca_cert_path; - } - } - + let (relay_tls, relay_tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let request_id = transfer_commence_request.session_id.to_string(); let result = asset_transfer_call( relay_host, @@ -883,32 +867,12 @@ async fn asset_transfer_call( use_tls: bool, tlsca_cert_path: String, ) -> Result, Box> { - let client_addr = format!("http://{}:{}", relay_host, relay_port); - let mut satp_client; - if use_tls { - let pem = tokio::fs::read(tlsca_cert_path).await?; - let ca = Certificate::from_pem(pem); - - let tls = ClientTlsConfig::new() - .ca_certificate(ca) - .domain_name(relay_host); - - let channel = Channel::from_shared(client_addr)? - .tls_config(tls)? - .connect() - .await?; - - satp_client = SatpClient::new(channel); - } else { - satp_client = SatpClient::connect(client_addr).await?; - } - + let satp_client: Result, _> = create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await; println!("Transfer commence request: {:?}", transfer_commence_request); - let response = satp_client.transfer_commence(transfer_commence_request).await?; + let response = satp_client.unwrap().transfer_commence(transfer_commence_request); Ok(response) } - // Sends a request to the remote relay fn spawn_send_event_subscription_request( conf: config::Config, diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 592f5f4868..23e1fa4f70 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -1,12 +1,16 @@ use config::Config; +use serde::de::DeserializeOwned; use serde::{Serialize, Deserialize}; use sled::IVec; +use tonic::transport::{ClientTlsConfig, Certificate, Channel}; use weaverpb::common::state::{RequestState, request_state}; use weaverpb::networks::networks::{NetworkAssetTransfer}; +use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{TransferCommenceRequest, CommenceResponseRequest}; use crate::db::Database; -use crate::error; +use crate::error::{self, Error}; +use crate::relay_proto::LocationSegment; pub fn derive_transfer_commence_request(network_asset_transfer: NetworkAssetTransfer) -> TransferCommenceRequest { let session_id = "to_be_calculated_session_id"; @@ -25,7 +29,7 @@ pub fn derive_transfer_commence_request(network_asset_transfer: NetworkAssetTran return transfer_commence_request; } -pub fn create_commence_response_request() -> CommenceResponseRequest { +pub fn create_commence_response_request(transfer_commence_request: TransferCommenceRequest) -> CommenceResponseRequest { let commence_response_request = CommenceResponseRequest { message_type: "message_type1".to_string(), session_id: "session_id1".to_string(), @@ -91,10 +95,11 @@ pub fn log_request_in_remote_sapt_db(request_id: &String, value: T return db.set(&request_id, &value); } -pub fn get_request_from_remote_sapt_db<'a, T: Deserialize<'a>>(request_id: &String, conf: Config) -> T { +pub fn get_request_from_remote_sapt_db(request_id: &String, conf: Config) -> Result { let db = get_satp_requests_remote_db(conf); - let query: T = db.get::(request_id.to_string()) - .map_err(|e| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", e)))?; + let query: Result = db.get::(request_id.to_string()) + .map_err(|e| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", e))); + return query; } pub fn update_request_state_in_local_satp_db(request_id: String, new_status: request_state::Status, state: Option, conf: Config) { @@ -109,3 +114,49 @@ pub fn update_request_state_in_local_satp_db(request_id: String, new_status: req println!("Successfully written RequestState to database"); println!("{:?}\n", db.get::(request_id).unwrap()) } + +pub fn get_requesting_relay(transfer_commence_request: TransferCommenceRequest) -> String { + // TODO + return "Dummy_Relay".to_string(); +} + +pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { + let relays_table = conf.get_table("relays").unwrap(); + let mut relay_tls = false; + let mut relay_tlsca_cert_path = "".to_string(); + for (_relay_name, relay_spec) in relays_table { + let relay_uri = relay_spec.clone().try_into::().unwrap(); + if relay_host == relay_uri.hostname && relay_port == relay_uri.port { + relay_tls = relay_uri.tls; + relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + } + } + (relay_tls, relay_tlsca_cert_path) +} + +fn create_client_address (relay_host: String, relay_port: String) -> String { + return format!("http://{}:{}", relay_host, relay_port); +} + +pub async fn create_satp_client(relay_host: String, relay_port: String, use_tls: bool, tlsca_cert_path: String) -> Result, Box> { + let client_addr = create_client_address(relay_host.clone(), relay_port.clone()); + let satp_client; + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await?; + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(relay_host); + + let channel = Channel::from_shared(client_addr)? + .tls_config(tls)? + .connect() + .await?; + + satp_client = Ok(SatpClient::new(channel)); + } else { + satp_client = Ok(SatpClient::connect(client_addr).await?); + } + return satp_client; +} \ No newline at end of file diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 60f59e1c40..ee301975fb 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,6 +1,7 @@ // Internal generated modules use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::query::Query; +use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{TransferCommenceRequest, CommenceResponseRequest, LockAssertionRequest, LockAssertionReceiptRequest}; @@ -18,7 +19,7 @@ use tonic::{Request, Response, Status}; use tonic::transport::{Certificate, Channel, ClientTlsConfig}; -use super::satp_helper::create_commence_response_request; +use super::satp_helper::{create_commence_response_request, get_request_from_remote_sapt_db, get_requesting_relay}; #[derive(Debug, Default)] pub struct SatpService { @@ -35,32 +36,29 @@ impl Satp for SatpService { &self, request: Request ) -> Result, Status> { - println!( - "Got a TransferCommenceRequest from {:?} - {:?}", - request.remote_addr(), - request - ); + println!("Got a TransferCommenceRequest from {:?} - {:?}", request.remote_addr(), request); let transfer_commence_request = request.into_inner().clone(); let request_id = transfer_commence_request.session_id.to_string(); let conf = self.config_lock.read().await; - let request_logged: Result, crate::error::Error> = log_request_in_remote_sapt_db(&request_id, &transfer_commence_request, conf.clone()); + // TODO refactor + let request_logged: Result, Error> = log_request_in_remote_sapt_db(&request_id, &transfer_commence_request, conf.clone()); match request_logged { Ok(_) => println!( - "Successfully stored TransferCommenceRequest in local satp_db with request_id: {}", + "Successfully stored TransferCommenceRequest in remote satp_db with request_id: {}", request_id ), Err(e) => { // Internal failure of sled. Send Error response println!( - "Error storing TransferCommenceRequest in local satp_db for request_id: {}", + "Error storing TransferCommenceRequest in remote satp_db for request_id: {}", request_id ); let reply = Ok(Response::new(Ack { status: ack::Status::Error as i32, request_id: request_id, - message: format!("Error storing TransferCommenceRequest in local satp_db {:?}", e), + message: format!("Error storing TransferCommenceRequest in remote satp_db {:?}", e), })); println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); return reply; @@ -107,6 +105,32 @@ impl Satp for SatpService { request ); + let commence_response_request = request.into_inner().clone(); + let request_id = commence_response_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = log_request_in_remote_sapt_db(&request_id, &commence_response_request, conf.clone()); + match request_logged { + Ok(_) => println!( + "Successfully stored CommenceResponseRequest in remote satp_db with request_id: {}", + request_id + ), + Err(e) => { + // Internal failure of sled. Send Error response + println!( + "Error storing CommenceResponseRequest in remote satp_db for request_id: {}", + request_id + ); + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: request_id, + message: format!("Error storing CommenceResponseRequest in remote satp_db {:?}", e), + })); + println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); + return reply; + } + } let reply = Ok( Response::new(Ack { status: ack::Status::Error as i32, @@ -171,7 +195,7 @@ pub fn transfer_commence_helper( if is_valid_request { println!("The transfer commence request is valid\n"); - match send_commence_response_helper(&request_id, conf) { + match send_commence_response_helper(transfer_commence_request, conf) { Ok(ack) => { println!("Ack transfer commence request."); let reply = Ok(ack); @@ -198,18 +222,23 @@ pub fn transfer_commence_helper( } fn send_commence_response_helper( - request_id: &String, + transfer_commence_request: TransferCommenceRequest, conf: config::Config ) -> Result { - let query: Query = remote_satp_db - .get::(request_id.to_string()) - .map_err(|e| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", e)))?; + + let request_id = &transfer_commence_request.session_id.to_string(); + // let network_asset_transfer: Result = get_request_from_remote_sapt_db(request_id, conf.clone()); + + // let query: Query = remote_satp_db + // .get::(request_id.to_string()) + // .map_err(|e| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", e)))?; let relays_table = conf.get_table("relays")?; + let requesting_relay = get_requesting_relay(transfer_commence_request.clone()); let relay_uri = relays_table - .get(&query.requesting_relay.to_string()) + .get(&requesting_relay.to_string()) .ok_or(Error::Simple("Relay name not found".to_string()))?; let uri = relay_uri.clone().try_into::()?; - let commence_response_request = create_commence_response_request(); + let commence_response_request = create_commence_response_request(transfer_commence_request.clone()); spawn_send_commence_response( commence_response_request, From c976683b69704da8056fbcd24793406277541a9a Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Sun, 2 Jul 2023 13:24:43 +0100 Subject: [PATCH 06/59] initial commit --- .../relay/src/services/network_service.rs | 60 +++++++++---------- weaver/core/relay/src/services/satp_helper.rs | 10 ++-- .../core/relay/src/services/satp_service.rs | 51 +++++----------- 3 files changed, 49 insertions(+), 72 deletions(-) diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 9bb6fdf511..347762d000 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -426,8 +426,8 @@ impl Network for NetworkService { ); let conf = self.config_lock.read().await.clone(); let network_asset_transfer = request.into_inner().clone(); - // TODO: request_id should be the hash of network_asset_transfer - let request_id = network_asset_transfer.requesting_relay.to_string(); + let transfer_commence_request: TransferCommenceRequest = derive_transfer_commence_request(network_asset_transfer.clone()); + let request_id = transfer_commence_request.session_id.to_string(); // TODO refactor let request_logged: Result, crate::error::Error> = log_request_in_local_sapt_db(&request_id, &network_asset_transfer, conf.clone()); match request_logged { @@ -479,7 +479,6 @@ impl Network for NetworkService { } } - let transfer_commence_request: TransferCommenceRequest = derive_transfer_commence_request(network_asset_transfer.clone()); let parsed_address = parse_address(network_asset_transfer.address.to_string()); match parsed_address { Ok(address) => { @@ -495,7 +494,7 @@ impl Network for NetworkService { let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id, - message: "".to_string(), + message: "Ack of the asset transfer request".to_string(), }; println!("Sending Ack of the asset transfer request back to network: {:?}\n", reply); Ok(Response::new(reply)) @@ -505,7 +504,7 @@ impl Network for NetworkService { let reply = Ack { status: ack::Status::Error as i32, request_id: request_id, - message: format!("Error: {:?}", e), + message: format!("Error: Ack of the asset transfer request {:?}", e), }; println!("Sending Ack back with an error to network: {:?}\n", reply); Ok(Response::new(reply)) @@ -798,28 +797,43 @@ async fn data_transfer_call( fn spawn_send_asset_transfer_request( conf: config::Config, transfer_commence_request: TransferCommenceRequest, - relay_host: String, - relay_port: String, + receiver_relay_host: String, + receiver_relay_port: String, ) { - println!("Sending asset transfer request to receiving gateway: {:?}:{:?}", relay_host, relay_port); - // Spawning new thread to make the data_transfer_call to receiving gateway + println!("Sending asset transfer request to receiver gateway: {:?}:{:?}", receiver_relay_host, receiver_relay_port); + // Spawning new thread to make the asset_transfer_call to receiver gateway tokio::spawn(async move { - let (relay_tls, relay_tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let (use_tls, relay_tlsca_cert_path) = get_relay_params(receiver_relay_host.clone(), receiver_relay_port.clone(), conf.clone()); let request_id = transfer_commence_request.session_id.to_string(); let result = asset_transfer_call( - relay_host, - relay_port, - transfer_commence_request, - relay_tls, + receiver_relay_host, + receiver_relay_port, + use_tls, relay_tlsca_cert_path.to_string(), + transfer_commence_request.clone(), ) .await; - println!("Received Ack from receiving gateway: {:?}\n", result); + + println!("Received Ack from receiver gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the receiving gateway log_result(&request_id, result, conf); }); } +// Call the transfer_commence endpoint on the receiver gateway +async fn asset_transfer_call( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + transfer_commence_request: TransferCommenceRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!("Sending the transfer commence request: {:?}", transfer_commence_request.clone()); + let response = satp_client.transfer_commence(transfer_commence_request.clone()).await?; + Ok(response) +} + fn log_result(request_id: &String, result: Result, Box>, conf: Config) { match result { Ok(ack_response) => { @@ -850,27 +864,13 @@ fn log_result(request_id: &String, result: Result, Box> )), conf) } - } + }, Err(result_error) => update_request_state_in_local_satp_db( request_id.to_string(), request_state::Status::Error, Some(request_state::State::Error(format!("{:?}", result_error))), conf) } - -} -// Call to remote relay for the data transfer protocol. -async fn asset_transfer_call( - relay_host: String, - relay_port: String, - transfer_commence_request: TransferCommenceRequest, - use_tls: bool, - tlsca_cert_path: String, -) -> Result, Box> { - let satp_client: Result, _> = create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await; - println!("Transfer commence request: {:?}", transfer_commence_request); - let response = satp_client.unwrap().transfer_commence(transfer_commence_request); - Ok(response) } // Sends a request to the remote relay diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 23e1fa4f70..1cba12abcd 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -115,9 +115,9 @@ pub fn update_request_state_in_local_satp_db(request_id: String, new_status: req println!("{:?}\n", db.get::(request_id).unwrap()) } -pub fn get_requesting_relay(transfer_commence_request: TransferCommenceRequest) -> String { +pub fn get_requesting_relay_host_and_port(transfer_commence_request: TransferCommenceRequest) -> (String, String) { // TODO - return "Dummy_Relay".to_string(); + return ("localhost".to_string(), "9085".to_string()) } pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { @@ -154,9 +154,9 @@ pub async fn create_satp_client(relay_host: String, relay_port: String, use_tls: .connect() .await?; - satp_client = Ok(SatpClient::new(channel)); + satp_client = SatpClient::new(channel); } else { - satp_client = Ok(SatpClient::connect(client_addr).await?); + satp_client = SatpClient::connect(client_addr).await?; } - return satp_client; + return Ok(satp_client); } \ No newline at end of file diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index ee301975fb..49f19f4e6e 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,25 +1,19 @@ // Internal generated modules use weaverpb::common::ack::{ack, Ack}; -use weaverpb::common::query::Query; -use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{TransferCommenceRequest, CommenceResponseRequest, LockAssertionRequest, LockAssertionReceiptRequest}; // Internal modules -use crate::db::Database; use crate::error::Error; -use crate::relay_proto::{LocationSegment}; -use crate::services::satp_helper::log_request_in_remote_sapt_db; +use crate::services::satp_helper::{log_request_in_remote_sapt_db, log_request_in_local_sapt_db}; // external modules use config; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; - use tonic::transport::{Certificate, Channel, ClientTlsConfig}; - -use super::satp_helper::{create_commence_response_request, get_request_from_remote_sapt_db, get_requesting_relay}; +use super::satp_helper::{create_commence_response_request, get_requesting_relay_host_and_port, get_relay_params}; #[derive(Debug, Default)] pub struct SatpService { @@ -65,14 +59,6 @@ impl Satp for SatpService { } } - // // Database access/storage - // let remote_satp_db = Database { - // db_path: conf.get_str("db_satp_path").unwrap(), - // db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - // db_open_retry_backoff_msec: conf - // .get_int("db_open_retry_backoff_msec") - // .unwrap_or(10) as u32, - // }; match transfer_commence_helper(transfer_commence_request, conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); @@ -110,22 +96,22 @@ impl Satp for SatpService { let conf = self.config_lock.read().await; // TODO refactor - let request_logged: Result, Error> = log_request_in_remote_sapt_db(&request_id, &commence_response_request, conf.clone()); + let request_logged: Result, Error> = log_request_in_local_sapt_db(&request_id, &commence_response_request, conf.clone()); match request_logged { Ok(_) => println!( - "Successfully stored CommenceResponseRequest in remote satp_db with request_id: {}", + "Successfully stored CommenceResponseRequest in local satp_db with request_id: {}", request_id ), Err(e) => { // Internal failure of sled. Send Error response println!( - "Error storing CommenceResponseRequest in remote satp_db for request_id: {}", + "Error storing CommenceResponseRequest in local satp_db for request_id: {}", request_id ); let reply = Ok(Response::new(Ack { status: ack::Status::Error as i32, request_id: request_id, - message: format!("Error storing CommenceResponseRequest in remote satp_db {:?}", e), + message: format!("Error storing CommenceResponseRequest in local satp_db {:?}", e), })); println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); return reply; @@ -134,7 +120,7 @@ impl Satp for SatpService { let reply = Ok( Response::new(Ack { status: ack::Status::Error as i32, - request_id: "xxxxxxxxx".to_string(), + request_id: request_id.to_string(), message: format!("Error: Not implemented yet."), }) ); @@ -227,30 +213,21 @@ fn send_commence_response_helper( ) -> Result { let request_id = &transfer_commence_request.session_id.to_string(); - // let network_asset_transfer: Result = get_request_from_remote_sapt_db(request_id, conf.clone()); - - // let query: Query = remote_satp_db - // .get::(request_id.to_string()) - // .map_err(|e| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", e)))?; - let relays_table = conf.get_table("relays")?; - let requesting_relay = get_requesting_relay(transfer_commence_request.clone()); - let relay_uri = relays_table - .get(&requesting_relay.to_string()) - .ok_or(Error::Simple("Relay name not found".to_string()))?; - let uri = relay_uri.clone().try_into::()?; + let (requesting_relay_host, requesting_relay_port) = get_requesting_relay_host_and_port(transfer_commence_request.clone()); + let (use_tls, relay_tlsca_cert_path) = get_relay_params(requesting_relay_host.clone(), requesting_relay_port.clone(), conf.clone()); let commence_response_request = create_commence_response_request(transfer_commence_request.clone()); spawn_send_commence_response( commence_response_request, - uri.hostname.to_string(), - uri.port.to_string(), - uri.tls, - uri.tlsca_cert_path.to_string(), + requesting_relay_host, + requesting_relay_port, + use_tls, + relay_tlsca_cert_path, ); let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), - message: "".to_string(), + message: "Ack of the Commence Response request".to_string(), }; return Ok(reply); From 7a99c0d30f3b7f628a6e678b57504555f850b863 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Sun, 2 Jul 2023 14:17:06 +0100 Subject: [PATCH 07/59] initial commit --- .../relay/src/services/network_service.rs | 86 +------------ weaver/core/relay/src/services/satp_helper.rs | 115 ++++++++++++++++++ .../core/relay/src/services/satp_service.rs | 58 +-------- 3 files changed, 123 insertions(+), 136 deletions(-) diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 347762d000..318aed9f13 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -8,7 +8,7 @@ use weaverpb::common::state::{request_state, RequestState}; use weaverpb::common::events::{EventSubscription, event_subscription_state, EventSubscriptionState, EventSubOperation, event_publication, EventPublication, EventStates}; use weaverpb::networks::networks::network_server::Network; use weaverpb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription, NetworkEventUnsubscription, NetworkAssetTransfer}; -use weaverpb::relay::satp::{TransferCommenceRequest}; +use weaverpb::relay::satp::{TransferCommenceRequest, CommenceResponseRequest}; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; @@ -16,7 +16,7 @@ use crate::relay_proto::{parse_address, LocationSegment}; // Internal modules use crate::db::Database; use crate::services::helpers::{update_event_subscription_status, driver_sign_subscription_helper, try_mark_request_state_deleted, mark_event_states_deleted, delete_event_pub_spec, get_event_publication_key, get_event_subscription_key}; -use crate::services::satp_helper::{derive_transfer_commence_request, log_request_state_in_local_sapt_db, log_request_in_local_sapt_db, update_request_state_in_local_satp_db, get_relay_params, create_satp_client}; +use crate::services::satp_helper::{derive_transfer_commence_request, log_request_state_in_local_sapt_db, log_request_in_local_sapt_db, update_request_state_in_local_satp_db, get_relay_params, create_satp_client, spawn_send_transfer_commence_request}; // External modules use config::{self, Config}; @@ -484,7 +484,7 @@ impl Network for NetworkService { Ok(address) => { // TODO: verify that host and port are valid // Spawns a child process to handle sending request - spawn_send_asset_transfer_request( + spawn_send_transfer_commence_request( conf, transfer_commence_request, address.location.hostname.to_string(), @@ -793,86 +793,6 @@ async fn data_transfer_call( Ok(response) } -// Sends a request to the receiving gateway -fn spawn_send_asset_transfer_request( - conf: config::Config, - transfer_commence_request: TransferCommenceRequest, - receiver_relay_host: String, - receiver_relay_port: String, -) { - println!("Sending asset transfer request to receiver gateway: {:?}:{:?}", receiver_relay_host, receiver_relay_port); - // Spawning new thread to make the asset_transfer_call to receiver gateway - tokio::spawn(async move { - let (use_tls, relay_tlsca_cert_path) = get_relay_params(receiver_relay_host.clone(), receiver_relay_port.clone(), conf.clone()); - let request_id = transfer_commence_request.session_id.to_string(); - let result = asset_transfer_call( - receiver_relay_host, - receiver_relay_port, - use_tls, - relay_tlsca_cert_path.to_string(), - transfer_commence_request.clone(), - ) - .await; - - println!("Received Ack from receiver gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the receiving gateway - log_result(&request_id, result, conf); - }); -} - -// Call the transfer_commence endpoint on the receiver gateway -async fn asset_transfer_call( - relay_host: String, - relay_port: String, - use_tls: bool, - tlsca_cert_path: String, - transfer_commence_request: TransferCommenceRequest, -) -> Result, Box> { - let mut satp_client: SatpClient = create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; - println!("Sending the transfer commence request: {:?}", transfer_commence_request.clone()); - let response = satp_client.transfer_commence(transfer_commence_request.clone()).await?; - Ok(response) -} - -fn log_result(request_id: &String, result: Result, Box>, conf: Config) { - match result { - Ok(ack_response) => { - let ack_response_into_inner = ack_response.into_inner().clone(); - // This match first checks if the status is valid. - match ack::Status::from_i32(ack_response_into_inner.status) { - Some(status) => match status { - ack::Status::Ok => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Pending, - None, - conf) - , - ack::Status::Error => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Error, - Some(request_state::State::Error( - ack_response_into_inner.message.to_string(), - )), - conf) - , - }, - None => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Error, - Some(request_state::State::Error( - "Status is not supported or is invalid".to_string(), - )), - conf) - } - }, - Err(result_error) => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Error, - Some(request_state::State::Error(format!("{:?}", result_error))), - conf) - } -} - // Sends a request to the remote relay fn spawn_send_event_subscription_request( conf: config::Config, diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 1cba12abcd..cda9a9c20b 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -2,7 +2,9 @@ use config::Config; use serde::de::DeserializeOwned; use serde::{Serialize, Deserialize}; use sled::IVec; +use tonic::Response; use tonic::transport::{ClientTlsConfig, Certificate, Channel}; +use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::state::{RequestState, request_state}; use weaverpb::networks::networks::{NetworkAssetTransfer}; use weaverpb::relay::satp::satp_client::SatpClient; @@ -12,6 +14,119 @@ use crate::db::Database; use crate::error::{self, Error}; use crate::relay_proto::LocationSegment; +// Sends a request to the receiving gateway +pub fn spawn_send_transfer_commence_request( + conf: config::Config, + transfer_commence_request: TransferCommenceRequest, + receiver_relay_host: String, + receiver_relay_port: String, +) { + println!("Sending transfer commence request to receiver gateway: {:?}:{:?}", receiver_relay_host, receiver_relay_port); + // Spawning new thread to make the asset_transfer_call to receiver gateway + tokio::spawn(async move { + let (use_tls, relay_tlsca_cert_path) = get_relay_params(receiver_relay_host.clone(), receiver_relay_port.clone(), conf.clone()); + let request_id = transfer_commence_request.session_id.to_string(); + let result = transfer_commence_call( + receiver_relay_host, + receiver_relay_port, + use_tls, + relay_tlsca_cert_path.to_string(), + transfer_commence_request.clone(), + ) + .await; + + println!("Received Ack from receiver gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the receiving gateway + log_result(&request_id, result, conf); + }); +} + +pub fn spawn_send_commence_response_request(commence_response_request: CommenceResponseRequest, requesting_relay_host: String, requesting_relay_port: String, use_tls: bool, relay_tlsca_cert_path: String, conf: Config) { + tokio::spawn(async move { + println!("Sending commence response back to sending gateway: Request ID = {:?}", commence_response_request.session_id); + let result = commence_response_call( + requesting_relay_host, + requesting_relay_port, + use_tls, + relay_tlsca_cert_path.to_string(), + commence_response_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = commence_response_request.session_id.to_string(); + log_result(&request_id, result, conf); + }); +} + +// Call the transfer_commence endpoint on the receiver gateway +pub async fn transfer_commence_call( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + transfer_commence_request: TransferCommenceRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!("Sending the transfer commence request: {:?}", transfer_commence_request.clone()); + let response = satp_client.transfer_commence(transfer_commence_request.clone()).await?; + Ok(response) +} + +// Call the commence_response endpoint on the sending gateway +pub async fn commence_response_call( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + commence_response_request: CommenceResponseRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!("Sending the commence response request: {:?}", commence_response_request.clone()); + let response = satp_client.commence_response(commence_response_request.clone()).await?; + Ok(response) +} + +pub fn log_result(request_id: &String, result: Result, Box>, conf: Config) { + match result { + Ok(ack_response) => { + let ack_response_into_inner = ack_response.into_inner().clone(); + // This match first checks if the status is valid. + match ack::Status::from_i32(ack_response_into_inner.status) { + Some(status) => match status { + ack::Status::Ok => update_request_state_in_local_satp_db( + request_id.to_string(), + request_state::Status::Pending, + None, + conf) + , + ack::Status::Error => update_request_state_in_local_satp_db( + request_id.to_string(), + request_state::Status::Error, + Some(request_state::State::Error( + ack_response_into_inner.message.to_string(), + )), + conf) + , + }, + None => update_request_state_in_local_satp_db( + request_id.to_string(), + request_state::Status::Error, + Some(request_state::State::Error( + "Status is not supported or is invalid".to_string(), + )), + conf) + } + }, + Err(result_error) => update_request_state_in_local_satp_db( + request_id.to_string(), + request_state::Status::Error, + Some(request_state::State::Error(format!("{:?}", result_error))), + conf) + } +} + pub fn derive_transfer_commence_request(network_asset_transfer: NetworkAssetTransfer) -> TransferCommenceRequest { let session_id = "to_be_calculated_session_id"; let transfer_commence_request = TransferCommenceRequest { diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 49f19f4e6e..ba9a4de03f 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -6,14 +6,14 @@ use weaverpb::relay::satp::{TransferCommenceRequest, CommenceResponseRequest, Lo // Internal modules use crate::error::Error; -use crate::services::satp_helper::{log_request_in_remote_sapt_db, log_request_in_local_sapt_db}; +use crate::services::satp_helper::{log_request_in_remote_sapt_db, log_request_in_local_sapt_db, create_satp_client, commence_response_call, log_result}; // external modules -use config; +use config::{self, Config}; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; use tonic::transport::{Certificate, Channel, ClientTlsConfig}; -use super::satp_helper::{create_commence_response_request, get_requesting_relay_host_and_port, get_relay_params}; +use super::satp_helper::{create_commence_response_request, get_requesting_relay_host_and_port, get_relay_params, spawn_send_commence_response_request}; #[derive(Debug, Default)] pub struct SatpService { @@ -217,70 +217,22 @@ fn send_commence_response_helper( let (use_tls, relay_tlsca_cert_path) = get_relay_params(requesting_relay_host.clone(), requesting_relay_port.clone(), conf.clone()); let commence_response_request = create_commence_response_request(transfer_commence_request.clone()); - spawn_send_commence_response( + spawn_send_commence_response_request( commence_response_request, requesting_relay_host, requesting_relay_port, use_tls, relay_tlsca_cert_path, + conf ); let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), message: "Ack of the Commence Response request".to_string(), }; - return Ok(reply); } -fn spawn_send_commence_response(commence_response_request: CommenceResponseRequest, requestor_host: String, requester_port: String, use_tls: bool, tlsca_cert_path: String) { - tokio::spawn(async move { - println!("Sending state back to sending gateway: Request ID = {:?}", commence_response_request.session_id); - // match state.state.as_ref().unwrap() { - // view_payload::State::View(v) => println!("View Meta: {:?}, View Data: {:?}", v.meta, base64::encode(&v.data)), - // view_payload::State::Error(e) => println!("Error: {:?}", e), - // } - let satp_client_addr = format!("http://{}:{}", requestor_host, requester_port); - if use_tls { - let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); - let ca = Certificate::from_pem(pem); - - let tls = ClientTlsConfig::new() - .ca_certificate(ca) - .domain_name(requestor_host); - - let channel = Channel::from_shared(satp_client_addr.to_string()).unwrap() - .tls_config(tls).expect(&format!("Error in TLS configuration for client: {}", satp_client_addr.to_string())) - .connect() - .await - .unwrap(); - - let mut satp_client_result = SatpClient::new(channel); - let response = satp_client_result.commence_response(commence_response_request).await; - println!("Response ACK from sending gateway={:?}\n", response); - } else { - let satp_client_result = SatpClient::connect(satp_client_addr).await; - match satp_client_result { - Ok(satp_client) => { - let response = satp_client.clone().commence_response(commence_response_request).await; - println!("Response ACK from sending gateway={:?}\n", response); - // Not returning anything here - } - Err(e) => { - // TODO: Add better error handling (Attempt a few times?) - println!( - "Failed to connect to client: ${:?}. Error: {}\n", - requester_port, - e.to_string() - ); - // TODO: Handle this error thorugh join handle after thread completes. - // Not actually returning anything here yet - } - } - } - }); -} - fn check_transfer_commence_request(transfer_commence_request: TransferCommenceRequest) -> bool { //TODO true From 2dd8ff099c730261039be5e9804f62ed9839f7ad Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Sun, 2 Jul 2023 14:45:53 +0100 Subject: [PATCH 08/59] initial commit --- .../relay/src/services/network_service.rs | 10 ++--- weaver/core/relay/src/services/satp_helper.rs | 11 +++++ .../core/relay/src/services/satp_service.rs | 40 +++++-------------- 3 files changed, 23 insertions(+), 38 deletions(-) diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 318aed9f13..63c0a08ce2 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -1,6 +1,3 @@ -use std::error::Error; - -use futures::TryFutureExt; // Internal generated modules use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::query::Query; @@ -8,18 +5,17 @@ use weaverpb::common::state::{request_state, RequestState}; use weaverpb::common::events::{EventSubscription, event_subscription_state, EventSubscriptionState, EventSubOperation, event_publication, EventPublication, EventStates}; use weaverpb::networks::networks::network_server::Network; use weaverpb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription, NetworkEventUnsubscription, NetworkAssetTransfer}; -use weaverpb::relay::satp::{TransferCommenceRequest, CommenceResponseRequest}; +use weaverpb::relay::satp::{TransferCommenceRequest}; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; -use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; use crate::relay_proto::{parse_address, LocationSegment}; // Internal modules use crate::db::Database; use crate::services::helpers::{update_event_subscription_status, driver_sign_subscription_helper, try_mark_request_state_deleted, mark_event_states_deleted, delete_event_pub_spec, get_event_publication_key, get_event_subscription_key}; -use crate::services::satp_helper::{derive_transfer_commence_request, log_request_state_in_local_sapt_db, log_request_in_local_sapt_db, update_request_state_in_local_satp_db, get_relay_params, create_satp_client, spawn_send_transfer_commence_request}; +use crate::services::satp_helper::{derive_transfer_commence_request, log_request_state_in_local_sapt_db, log_request_in_local_sapt_db, spawn_send_transfer_commence_request}; // External modules -use config::{self, Config}; +use config::{self}; use sled::open; use tokio::sync::RwLock; use tonic::{Code, Request, Response, Status}; diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index cda9a9c20b..35a452a85d 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -127,6 +127,17 @@ pub fn log_result(request_id: &String, result: Result, Box Result, tonic::Status> { + println!("{}: {}", error_message, request_id); + let reply: Result, tonic::Status> = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: request_id, + message: format!("{} {:?}", error_message, e), + })); + println!("Sending Ack back with an error: {:?}\n", reply); + return reply; +} + pub fn derive_transfer_commence_request(network_asset_transfer: NetworkAssetTransfer) -> TransferCommenceRequest { let session_id = "to_be_calculated_session_id"; let transfer_commence_request = TransferCommenceRequest { diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index ba9a4de03f..9f84c5dad4 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,18 +1,15 @@ // Internal generated modules use weaverpb::common::ack::{ack, Ack}; -use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{TransferCommenceRequest, CommenceResponseRequest, LockAssertionRequest, LockAssertionReceiptRequest}; // Internal modules use crate::error::Error; -use crate::services::satp_helper::{log_request_in_remote_sapt_db, log_request_in_local_sapt_db, create_satp_client, commence_response_call, log_result}; +use crate::services::satp_helper::{log_request_in_remote_sapt_db, log_request_in_local_sapt_db, create_ack_error_message}; // external modules -use config::{self, Config}; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; -use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use super::satp_helper::{create_commence_response_request, get_requesting_relay_host_and_port, get_relay_params, spawn_send_commence_response_request}; #[derive(Debug, Default)] @@ -36,25 +33,14 @@ impl Satp for SatpService { let request_id = transfer_commence_request.session_id.to_string(); let conf = self.config_lock.read().await; - // TODO refactor - let request_logged: Result, Error> = log_request_in_remote_sapt_db(&request_id, &transfer_commence_request, conf.clone()); - match request_logged { - Ok(_) => println!( - "Successfully stored TransferCommenceRequest in remote satp_db with request_id: {}", - request_id - ), + match log_request_in_remote_sapt_db(&request_id, &transfer_commence_request, conf.clone()) { + Ok(_) => { + println!("Successfully stored TransferCommenceRequest in remote satp_db with request_id: {}", request_id); + }, Err(e) => { // Internal failure of sled. Send Error response - println!( - "Error storing TransferCommenceRequest in remote satp_db for request_id: {}", - request_id - ); - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: request_id, - message: format!("Error storing TransferCommenceRequest in remote satp_db {:?}", e), - })); - println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); + let error_message = "Error storing TransferCommenceRequest in remote satp_db for request_id".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); return reply; } } @@ -66,16 +52,8 @@ impl Satp for SatpService { reply } Err(e) => { - println!("Transfer commence failed."); - let reply = Ok( - // TODO: remove the hardcoded value - Response::new(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error: Transfer initiation failed. {:?}", e), - }) - ); - println!("Sending back Ack: {:?}\n", reply); + let error_message = "Transfer commence failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); reply } } From 4a0f236996ddc72de04f6efb98f6309bb2f493c5 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Sun, 2 Jul 2023 16:02:47 +0100 Subject: [PATCH 09/59] intial commit --- .../relay/src/services/network_service.rs | 318 ++++++++++++------ weaver/core/relay/src/services/satp_helper.rs | 181 +++++++--- .../core/relay/src/services/satp_service.rs | 129 +++---- 3 files changed, 417 insertions(+), 211 deletions(-) diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 63c0a08ce2..8300e439b5 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -1,18 +1,31 @@ // Internal generated modules +use crate::relay_proto::{parse_address, LocationSegment}; use weaverpb::common::ack::{ack, Ack}; +use weaverpb::common::events::{ + event_publication, event_subscription_state, EventPublication, EventStates, EventSubOperation, + EventSubscription, EventSubscriptionState, +}; use weaverpb::common::query::Query; use weaverpb::common::state::{request_state, RequestState}; -use weaverpb::common::events::{EventSubscription, event_subscription_state, EventSubscriptionState, EventSubOperation, event_publication, EventPublication, EventStates}; use weaverpb::networks::networks::network_server::Network; -use weaverpb::networks::networks::{DbName, GetStateMessage, NetworkQuery, RelayDatabase, NetworkEventSubscription, NetworkEventUnsubscription, NetworkAssetTransfer}; -use weaverpb::relay::satp::{TransferCommenceRequest}; +use weaverpb::networks::networks::{ + DbName, GetStateMessage, NetworkAssetTransfer, NetworkEventSubscription, + NetworkEventUnsubscription, NetworkQuery, RelayDatabase, +}; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; -use crate::relay_proto::{parse_address, LocationSegment}; +use weaverpb::relay::satp::TransferCommenceRequest; // Internal modules use crate::db::Database; -use crate::services::helpers::{update_event_subscription_status, driver_sign_subscription_helper, try_mark_request_state_deleted, mark_event_states_deleted, delete_event_pub_spec, get_event_publication_key, get_event_subscription_key}; -use crate::services::satp_helper::{derive_transfer_commence_request, log_request_state_in_local_sapt_db, log_request_in_local_sapt_db, spawn_send_transfer_commence_request}; +use crate::services::helpers::{ + delete_event_pub_spec, driver_sign_subscription_helper, get_event_publication_key, + get_event_subscription_key, mark_event_states_deleted, try_mark_request_state_deleted, + update_event_subscription_status, +}; +use crate::services::satp_helper::{ + derive_transfer_commence_request, log_request_in_local_sapt_db, + log_request_state_in_local_sapt_db, spawn_send_transfer_commence_request, +}; // External modules use config::{self}; @@ -40,29 +53,38 @@ impl Network for NetworkService { let db = Database { db_path: conf.get_str("db_path").unwrap(), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) + as u32, }; let request_id = request.into_inner().request_id; let result = db.get::(request_id.to_string()); match result { Ok(request_state) => { - println!("Sending back RequestState to network: Request ID = {:?}, Status = {:?}", - request_state.request_id, - request_state.status - ); + println!( + "Sending back RequestState to network: Request ID = {:?}, Status = {:?}", + request_state.request_id, request_state.status + ); match request_state.state.as_ref() { Some(state) => { // Because already state is passed to client, deleting the state if status is completed or error - try_mark_request_state_deleted(request_state.clone(), request_id.to_string(), db); + try_mark_request_state_deleted( + request_state.clone(), + request_id.to_string(), + db, + ); match state { - request_state::State::View(v) => println!("View Meta: {:?}, View Data: {:?}", v.meta, base64::encode(&v.data)), + request_state::State::View(v) => println!( + "View Meta: {:?}, View Data: {:?}", + v.meta, + base64::encode(&v.data) + ), request_state::State::Error(e) => println!("Error: {:?}", e), } - }, - None => {}, + } + None => {} } return Ok(Response::new(request_state)); - }, + } Err(e) => Err(Status::new( Code::NotFound, format!("Request not found. Error: {:?}", e), @@ -83,7 +105,7 @@ impl Network for NetworkService { while let Some(key) = curr_key { // println!("{:?}", key); let decoded_key = std::str::from_utf8(&key.0[..]).unwrap(); - + if decoded_key.to_string().contains(&"event_sub".to_string()) { let decoded_result: Result = bincode::deserialize(&key.1[..]); @@ -128,7 +150,8 @@ impl Network for NetworkService { let db = Database { db_path: conf.get_str("db_path").unwrap(), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) + as u32, }; let request_id = Uuid::new_v4(); @@ -172,7 +195,7 @@ impl Network for NetworkService { network_query, request_id.to_string(), address.location.hostname.to_string(), - address.location.port.to_string() + address.location.port.to_string(), ); // Send Ack back to network while request is happening in a thread let reply = Ack { @@ -195,9 +218,12 @@ impl Network for NetworkService { } } } - + // Subscribe Event Endpoints - async fn subscribe_event(&self, request: Request) -> Result, Status> { + async fn subscribe_event( + &self, + request: Request, + ) -> Result, Status> { println!( "Got a Network Event Subscription request from {:?} - {:?}", request.remote_addr(), @@ -208,15 +234,21 @@ impl Network for NetworkService { let db = Database { db_path: conf.get_str("db_path").unwrap(), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) + as u32, }; let request_id = Uuid::new_v4(); let network_event_subscription = request.into_inner().clone(); - + let mut event_publication_specs: Vec = Vec::new(); - event_publication_specs.push(network_event_subscription.event_publication_spec.clone().expect("Event publication spec not found in NetworkEventSubscription request")); - + event_publication_specs.push( + network_event_subscription + .event_publication_spec + .clone() + .expect("Event publication spec not found in NetworkEventSubscription request"), + ); + // Initial request state stored in DB. let target: EventSubscriptionState = EventSubscriptionState { status: event_subscription_state::Status::SubscribePendingAck as i32, @@ -224,11 +256,14 @@ impl Network for NetworkService { publishing_request_id: "".to_string(), message: "".to_string(), event_matcher: network_event_subscription.event_matcher.clone(), - event_publication_specs: event_publication_specs + event_publication_specs: event_publication_specs, }; - + // Create EventSubscription - let network_query = network_event_subscription.query.clone().expect("No query passed with NetworkEventSubscription request"); + let network_query = network_event_subscription + .query + .clone() + .expect("No query passed with NetworkEventSubscription request"); let relay_name = conf.get_str("name").unwrap(); let query: Query = Query { policy: network_query.policy, @@ -247,21 +282,38 @@ impl Network for NetworkService { query: Some(query), operation: EventSubOperation::Subscribe as i32, }; - let event_publication_spec = network_event_subscription.event_publication_spec.clone().expect("No Event Publication Specification passed with NetworkEventSubscription request"); + let event_publication_spec = network_event_subscription + .event_publication_spec + .clone() + .expect( + "No Event Publication Specification passed with NetworkEventSubscription request", + ); - return event_subscription_helper(event_subscription, event_publication_spec, target, request_id.to_string(), db, conf).await; + return event_subscription_helper( + event_subscription, + event_publication_spec, + target, + request_id.to_string(), + db, + conf, + ) + .await; } - + async fn get_event_subscription_state( &self, request: Request, ) -> Result, Status> { - println!("\nReceived GetEventSubscriptionState request from network: {:?}", request); + println!( + "\nReceived GetEventSubscriptionState request from network: {:?}", + request + ); let conf = self.config_lock.read().await.clone(); let db = Database { db_path: conf.get_str("db_path").unwrap(), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) + as u32, }; let event_sub_key = get_event_subscription_key(request.into_inner().request_id); let result = db.get::(event_sub_key.to_string()); @@ -270,19 +322,23 @@ impl Network for NetworkService { match event_subscription_state::Status::from_i32(fetched_event_sub_state.status) { Some(status) => match status { event_subscription_state::Status::Unsubscribed => { - let result = db.unset::(event_sub_key.to_string()); + let result = + db.unset::(event_sub_key.to_string()); match result { Ok(old_state) => { - println!("Removed EventSubscription from database: {:?}", old_state); - }, + println!( + "Removed EventSubscription from database: {:?}", + old_state + ); + } Err(e) => { println!("EventSubscription Request not found. Error: {:?}", e); } } - }, - _ => {}, + } + _ => {} }, - None => {}, + None => {} } println!("Sending back EventSubscriptionState to network: Request ID = {:?}, Status = {:?}", @@ -290,7 +346,7 @@ impl Network for NetworkService { fetched_event_sub_state.status ); return Ok(Response::new(fetched_event_sub_state)); - }, + } Err(e) => Err(Status::new( Code::NotFound, format!("Event Subscription Request not found. Error: {:?}", e), @@ -298,7 +354,10 @@ impl Network for NetworkService { } } // Unsubscribe Event Endpoints - async fn unsubscribe_event(&self, request: Request) -> Result, Status> { + async fn unsubscribe_event( + &self, + request: Request, + ) -> Result, Status> { println!( "Got a Network Event Unubscription request from {:?} - {:?}", request.remote_addr(), @@ -309,22 +368,29 @@ impl Network for NetworkService { let db = Database { db_path: conf.get_str("db_path").unwrap(), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) + as u32, }; - + let net_event_sub = request.into_inner().clone(); - let network_event_subscription = net_event_sub.request.clone().expect("No network event subscription passed"); + let network_event_subscription = net_event_sub + .request + .clone() + .expect("No network event subscription passed"); let request_id = net_event_sub.request_id.to_string(); - let requested_unsub_pub_spec = network_event_subscription.event_publication_spec.clone().expect("No event publication spec provided for unsubscription request."); - + let requested_unsub_pub_spec = network_event_subscription + .event_publication_spec + .clone() + .expect("No event publication spec provided for unsubscription request."); + let delete_pub_spec_status = delete_event_pub_spec( - request_id.to_string(), - requested_unsub_pub_spec, + request_id.to_string(), + requested_unsub_pub_spec, conf.get_str("db_path").unwrap().to_string(), conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32 + conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, ); - + if delete_pub_spec_status == 0 { let reply = Ack { status: ack::Status::Ok as i32, @@ -343,8 +409,13 @@ impl Network for NetworkService { Ok(Response::new(reply)) } else { let mut event_publication_specs: Vec = Vec::new(); - event_publication_specs.push(network_event_subscription.event_publication_spec.clone().expect("Event publication spec not found in NetworkEventSubscription request")); - + event_publication_specs.push( + network_event_subscription + .event_publication_spec + .clone() + .expect("Event publication spec not found in NetworkEventSubscription request"), + ); + // Initial request state stored in DB. let target: EventSubscriptionState = EventSubscriptionState { status: event_subscription_state::Status::UnsubscribePendingAck as i32, @@ -352,11 +423,14 @@ impl Network for NetworkService { publishing_request_id: request_id.to_string(), message: "".to_string(), event_matcher: network_event_subscription.event_matcher.clone(), - event_publication_specs: event_publication_specs + event_publication_specs: event_publication_specs, }; - + // Create EventSubscription - let network_query = network_event_subscription.query.clone().expect("No query passed with NetworkEventSubscription request"); + let network_query = network_event_subscription + .query + .clone() + .expect("No query passed with NetworkEventSubscription request"); let relay_name = conf.get_str("name").unwrap(); let query: Query = Query { policy: network_query.policy, @@ -375,46 +449,76 @@ impl Network for NetworkService { query: Some(query), operation: EventSubOperation::Unsubscribe as i32, }; - let event_publication_spec = network_event_subscription.event_publication_spec.clone().expect("No Event Publication Specification passed with NetworkEventSubscription request"); + let event_publication_spec = network_event_subscription + .event_publication_spec + .clone() + .expect( + "No Event Publication Specification passed with NetworkEventSubscription request", + ); - return event_subscription_helper(event_subscription, event_publication_spec, target, request_id.to_string(), db, conf).await; + return event_subscription_helper( + event_subscription, + event_publication_spec, + target, + request_id.to_string(), + db, + conf, + ) + .await; } } - + // Fetch EventStates for given subscription request identified by request_id. async fn get_event_states( &self, request: Request, ) -> Result, Status> { - println!("\nReceived GetEventStates request from network: {:?}", request); + println!( + "\nReceived GetEventStates request from network: {:?}", + request + ); let conf = self.config_lock.read().await.clone(); let db = Database { db_path: conf.get_str("db_path").unwrap(), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, + db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) + as u32, }; let request_id = request.into_inner().request_id; let event_publish_key = get_event_publication_key(request_id.to_string()); let result = db.get::(event_publish_key.to_string()); match result { Ok(fetched_event_states) => { - mark_event_states_deleted(fetched_event_states.clone(), request_id.to_string(), event_publish_key.to_string(), db); - println!("Sending back EventStates to network: Request ID = {:?}: {:?}", - request_id.to_string(), - fetched_event_states.clone() - ); + mark_event_states_deleted( + fetched_event_states.clone(), + request_id.to_string(), + event_publish_key.to_string(), + db, + ); + println!( + "Sending back EventStates to network: Request ID = {:?}: {:?}", + request_id.to_string(), + fetched_event_states.clone() + ); return Ok(Response::new(fetched_event_states)); - }, + } Err(e) => Err(Status::new( Code::NotFound, - format!("EventStates not found for request_id: {}. Error: {:?}", request_id.to_string(), e), + format!( + "EventStates not found for request_id: {}. Error: {:?}", + request_id.to_string(), + e + ), )), } } /// request_asset_transfer is called from the client to query the sending gateway to transfer an asset. /// The request info/state machine is stored in a db on the sending gateway - async fn request_asset_transfer(&self, request: Request) -> Result, Status> { + async fn request_asset_transfer( + &self, + request: Request, + ) -> Result, Status> { println!( "Got a NetworkAssetTransfer request from {:?} - {:?}", request.remote_addr(), @@ -422,10 +526,12 @@ impl Network for NetworkService { ); let conf = self.config_lock.read().await.clone(); let network_asset_transfer = request.into_inner().clone(); - let transfer_commence_request: TransferCommenceRequest = derive_transfer_commence_request(network_asset_transfer.clone()); + let transfer_commence_request: TransferCommenceRequest = + derive_transfer_commence_request(network_asset_transfer.clone()); let request_id = transfer_commence_request.session_id.to_string(); // TODO refactor - let request_logged: Result, crate::error::Error> = log_request_in_local_sapt_db(&request_id, &network_asset_transfer, conf.clone()); + let request_logged: Result, crate::error::Error> = + log_request_in_local_sapt_db(&request_id, &network_asset_transfer, conf.clone()); match request_logged { Ok(_) => println!( "Successfully stored NetworkAssetTransfer in local satp_db with request_id: {}", @@ -440,7 +546,10 @@ impl Network for NetworkService { let reply = Ok(Response::new(Ack { status: ack::Status::Error as i32, request_id: request_id, - message: format!("Error storing NetworkAssetTransfer in local satp_db {:?}", e), + message: format!( + "Error storing NetworkAssetTransfer in local satp_db {:?}", + e + ), })); println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); return reply; @@ -453,7 +562,8 @@ impl Network for NetworkService { request_id: request_id.clone(), state: None, }; - let request_state_logged: Result, crate::error::Error> = log_request_state_in_local_sapt_db(&request_id, &target, conf.clone()); + let request_state_logged: Result, crate::error::Error> = + log_request_state_in_local_sapt_db(&request_id, &target, conf.clone()); match request_state_logged { Ok(_) => println!( "Successfully stored RequestState in local satp_db with request_id: {}", @@ -484,7 +594,7 @@ impl Network for NetworkService { conf, transfer_commence_request, address.location.hostname.to_string(), - address.location.port.to_string() + address.location.port.to_string(), ); // Send Ack back to network while request is happening in a thread let reply = Ack { @@ -492,7 +602,10 @@ impl Network for NetworkService { request_id: request_id, message: "Ack of the asset transfer request".to_string(), }; - println!("Sending Ack of the asset transfer request back to network: {:?}\n", reply); + println!( + "Sending Ack of the asset transfer request back to network: {:?}\n", + reply + ); Ok(Response::new(reply)) } Err(e) => { @@ -507,7 +620,6 @@ impl Network for NetworkService { } } } - } async fn event_subscription_helper( @@ -519,19 +631,23 @@ async fn event_subscription_helper( conf: config::Config, ) -> Result, Status> { let event_subscription; - + // Check if driver is subscribing/unsubscribing match event_publication_spec.publication_target { Some(data) => match data { event_publication::PublicationTarget::Ctx(ctx) => { let driver_id = ctx.clone().driver_id.to_string(); - println!("Requesting Driver {} to sign", driver_id.clone().to_string()); + println!( + "Requesting Driver {} to sign", + driver_id.clone().to_string() + ); let result = driver_sign_subscription_helper( req_event_subscription.clone(), request_id.to_string(), driver_id.to_string(), conf.clone(), - ).await; + ) + .await; match result { Ok(signed_query) => { event_subscription = EventSubscription { @@ -548,12 +664,15 @@ async fn event_subscription_helper( message: format!("Error: {:?}", e), }; println!("Sending Ack back to network: {:?}\n", reply); - return Ok(Response::new(reply)) + return Ok(Response::new(reply)); } } } event_publication::PublicationTarget::AppUrl(app_url) => { - println!("Registering for Client using App URL: {}", app_url.to_string()); + println!( + "Registering for Client using App URL: {}", + app_url.to_string() + ); event_subscription = req_event_subscription; } }, @@ -565,10 +684,10 @@ async fn event_subscription_helper( message: format!("No Publication Target provided"), }; println!("Sending Ack back to network: {:?}\n", reply); - return Ok(Response::new(reply)) + return Ok(Response::new(reply)); } }; - + let event_sub_key = get_event_subscription_key(request_id.to_string()); let message_insert = db.set(&event_sub_key.to_string(), &target_status); // Kept this as a match as the error case returns an Ok. @@ -635,7 +754,10 @@ fn spawn_send_request( relay_host: String, relay_port: String, ) { - println!("Sending Query to remote relay: {:?}:{:?}", relay_host, relay_port); + println!( + "Sending Query to remote relay: {:?}:{:?}", + relay_host, relay_port + ); // Locally scoped function to update request status in db. This function is // called for the first time after an Ack is received from the remote relay. // A locally created RequestState with status Pending or Error is stored. @@ -797,13 +919,17 @@ fn spawn_send_event_subscription_request( relay_host: String, relay_port: String, ) { - println!("Sending EventSubscription to remote relay: {:?}:{:?}", relay_host, relay_port); - + println!( + "Sending EventSubscription to remote relay: {:?}:{:?}", + relay_host, relay_port + ); + // Spawning new thread to make the subscribe_event_call to remote relay tokio::spawn(async move { let db_path = conf.get_str("db_path").unwrap(); let db_open_max_retries = conf.get_int("db_open_max_retries").unwrap_or(500) as u32; - let db_open_retry_backoff_msec = conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32; + let db_open_retry_backoff_msec = + conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32; // Iterate through the relay entries in the configuration to find a match let relays_table = conf.get_table("relays").unwrap(); @@ -834,12 +960,12 @@ fn spawn_send_event_subscription_request( // This match first checks if the status is valid. match ack::Status::from_i32(ack_response_into_inner.status) { Some(status) => update_event_subscription_status( - request_id.to_string(), - status, - db_path.to_string(), - db_open_max_retries.clone(), - db_open_retry_backoff_msec.clone(), - ack_response_into_inner.message.to_string(), + request_id.to_string(), + status, + db_path.to_string(), + db_open_max_retries.clone(), + db_open_retry_backoff_msec.clone(), + ack_response_into_inner.message.to_string(), ), None => update_event_subscription_status( request_id.to_string(), @@ -875,21 +1001,21 @@ async fn suscribe_event_call( if use_tls { let pem = tokio::fs::read(tlsca_cert_path).await?; let ca = Certificate::from_pem(pem); - + let tls = ClientTlsConfig::new() .ca_certificate(ca) .domain_name(relay_host); - + let channel = Channel::from_shared(client_addr)? .tls_config(tls)? .connect() .await?; - + client = EventSubscribeClient::new(channel); } else { client = EventSubscribeClient::connect(client_addr).await?; } - + let event_subscription_request = tonic::Request::new(event_subscription); println!("EventSubscription: {:?}", event_subscription_request); let response = client.subscribe_event(event_subscription_request).await?; diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 35a452a85d..22ec333744 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -1,14 +1,14 @@ use config::Config; use serde::de::DeserializeOwned; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use sled::IVec; +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use tonic::Response; -use tonic::transport::{ClientTlsConfig, Certificate, Channel}; use weaverpb::common::ack::{ack, Ack}; -use weaverpb::common::state::{RequestState, request_state}; -use weaverpb::networks::networks::{NetworkAssetTransfer}; +use weaverpb::common::state::{request_state, RequestState}; +use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; -use weaverpb::relay::satp::{TransferCommenceRequest, CommenceResponseRequest}; +use weaverpb::relay::satp::{CommenceResponseRequest, TransferCommenceRequest}; use crate::db::Database; use crate::error::{self, Error}; @@ -21,10 +21,17 @@ pub fn spawn_send_transfer_commence_request( receiver_relay_host: String, receiver_relay_port: String, ) { - println!("Sending transfer commence request to receiver gateway: {:?}:{:?}", receiver_relay_host, receiver_relay_port); + println!( + "Sending transfer commence request to receiver gateway: {:?}:{:?}", + receiver_relay_host, receiver_relay_port + ); // Spawning new thread to make the asset_transfer_call to receiver gateway tokio::spawn(async move { - let (use_tls, relay_tlsca_cert_path) = get_relay_params(receiver_relay_host.clone(), receiver_relay_port.clone(), conf.clone()); + let (use_tls, relay_tlsca_cert_path) = get_relay_params( + receiver_relay_host.clone(), + receiver_relay_port.clone(), + conf.clone(), + ); let request_id = transfer_commence_request.session_id.to_string(); let result = transfer_commence_call( receiver_relay_host, @@ -37,13 +44,23 @@ pub fn spawn_send_transfer_commence_request( println!("Received Ack from receiver gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the receiving gateway - log_result(&request_id, result, conf); + log_request_result_in_local_satp_db(&request_id, result, conf); }); } -pub fn spawn_send_commence_response_request(commence_response_request: CommenceResponseRequest, requesting_relay_host: String, requesting_relay_port: String, use_tls: bool, relay_tlsca_cert_path: String, conf: Config) { +pub fn spawn_send_commence_response_request( + commence_response_request: CommenceResponseRequest, + requesting_relay_host: String, + requesting_relay_port: String, + use_tls: bool, + relay_tlsca_cert_path: String, + conf: Config, +) { tokio::spawn(async move { - println!("Sending commence response back to sending gateway: Request ID = {:?}", commence_response_request.session_id); + println!( + "Sending commence response back to sending gateway: Request ID = {:?}", + commence_response_request.session_id + ); let result = commence_response_call( requesting_relay_host, requesting_relay_port, @@ -56,7 +73,7 @@ pub fn spawn_send_commence_response_request(commence_response_request: CommenceR println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = commence_response_request.session_id.to_string(); - log_result(&request_id, result, conf); + log_request_result_in_local_satp_db(&request_id, result, conf); }); } @@ -68,9 +85,15 @@ pub async fn transfer_commence_call( tlsca_cert_path: String, transfer_commence_request: TransferCommenceRequest, ) -> Result, Box> { - let mut satp_client: SatpClient = create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; - println!("Sending the transfer commence request: {:?}", transfer_commence_request.clone()); - let response = satp_client.transfer_commence(transfer_commence_request.clone()).await?; + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the transfer commence request: {:?}", + transfer_commence_request.clone() + ); + let response = satp_client + .transfer_commence(transfer_commence_request.clone()) + .await?; Ok(response) } @@ -82,13 +105,23 @@ pub async fn commence_response_call( tlsca_cert_path: String, commence_response_request: CommenceResponseRequest, ) -> Result, Box> { - let mut satp_client: SatpClient = create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; - println!("Sending the commence response request: {:?}", commence_response_request.clone()); - let response = satp_client.commence_response(commence_response_request.clone()).await?; + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the commence response request: {:?}", + commence_response_request.clone() + ); + let response = satp_client + .commence_response(commence_response_request.clone()) + .await?; Ok(response) } -pub fn log_result(request_id: &String, result: Result, Box>, conf: Config) { +pub fn log_request_result_in_local_satp_db( + request_id: &String, + result: Result, Box>, + conf: Config, +) { match result { Ok(ack_response) => { let ack_response_into_inner = ack_response.into_inner().clone(); @@ -96,38 +129,44 @@ pub fn log_result(request_id: &String, result: Result, Box match status { ack::Status::Ok => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Pending, - None, - conf) - , + request_id.to_string(), + request_state::Status::Pending, + None, + conf, + ), ack::Status::Error => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Error, + request_id.to_string(), + request_state::Status::Error, Some(request_state::State::Error( ack_response_into_inner.message.to_string(), - )), - conf) - , + )), + conf, + ), }, None => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Error, + request_id.to_string(), + request_state::Status::Error, Some(request_state::State::Error( "Status is not supported or is invalid".to_string(), - )), - conf) + )), + conf, + ), } - }, + } Err(result_error) => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Error, - Some(request_state::State::Error(format!("{:?}", result_error))), - conf) + request_id.to_string(), + request_state::Status::Error, + Some(request_state::State::Error(format!("{:?}", result_error))), + conf, + ), } } -pub fn create_ack_error_message(request_id: String, error_message: String, e: Error) -> Result, tonic::Status> { +pub fn create_ack_error_message( + request_id: String, + error_message: String, + e: Error, +) -> Result, tonic::Status> { println!("{}: {}", error_message, request_id); let reply: Result, tonic::Status> = Ok(Response::new(Ack { status: ack::Status::Error as i32, @@ -138,8 +177,10 @@ pub fn create_ack_error_message(request_id: String, error_message: String, e: Er return reply; } -pub fn derive_transfer_commence_request(network_asset_transfer: NetworkAssetTransfer) -> TransferCommenceRequest { - let session_id = "to_be_calculated_session_id"; +pub fn derive_transfer_commence_request( + network_asset_transfer: NetworkAssetTransfer, +) -> TransferCommenceRequest { + let session_id = "to_be_calculated_session_id"; let transfer_commence_request = TransferCommenceRequest { message_type: "message_type1".to_string(), session_id: session_id.to_string(), @@ -149,13 +190,15 @@ pub fn derive_transfer_commence_request(network_asset_transfer: NetworkAssetTran hash_transfer_init_claims: "hash_transfer_init_claims1".to_string(), hash_prev_message: "hash_prev_message1".to_string(), client_transfer_number: "client_transfer_number1".to_string(), - client_signature: "client_signature1".to_string() + client_signature: "client_signature1".to_string(), }; return transfer_commence_request; } -pub fn create_commence_response_request(transfer_commence_request: TransferCommenceRequest) -> CommenceResponseRequest { +pub fn create_commence_response_request( + transfer_commence_request: TransferCommenceRequest, +) -> CommenceResponseRequest { let commence_response_request = CommenceResponseRequest { message_type: "message_type1".to_string(), session_id: "session_id1".to_string(), @@ -206,29 +249,50 @@ pub fn get_satp_requests_states_remote_db(conf: Config) -> Database { return db; } -pub fn log_request_state_in_local_sapt_db(request_id: &String, target: &RequestState, conf: Config) -> Result, error::Error>{ +pub fn log_request_state_in_local_sapt_db( + request_id: &String, + target: &RequestState, + conf: Config, +) -> Result, error::Error> { let db = get_satp_requests_states_local_db(conf); return db.set(&request_id, &target); } -pub fn log_request_in_local_sapt_db(request_id: &String, value: T, conf: Config) -> Result, error::Error>{ +pub fn log_request_in_local_sapt_db( + request_id: &String, + value: T, + conf: Config, +) -> Result, error::Error> { let db = get_satp_requests_local_db(conf); return db.set(&request_id, &value); } -pub fn log_request_in_remote_sapt_db(request_id: &String, value: T, conf: Config) -> Result, error::Error>{ +pub fn log_request_in_remote_sapt_db( + request_id: &String, + value: T, + conf: Config, +) -> Result, error::Error> { let db = get_satp_requests_remote_db(conf); return db.set(&request_id, &value); } -pub fn get_request_from_remote_sapt_db(request_id: &String, conf: Config) -> Result { +pub fn get_request_from_remote_sapt_db( + request_id: &String, + conf: Config, +) -> Result { let db = get_satp_requests_remote_db(conf); - let query: Result = db.get::(request_id.to_string()) - .map_err(|e| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", e))); + let query: Result = db + .get::(request_id.to_string()) + .map_err(|e| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", e))); return query; } -pub fn update_request_state_in_local_satp_db(request_id: String, new_status: request_state::Status, state: Option, conf: Config) { +pub fn update_request_state_in_local_satp_db( + request_id: String, + new_status: request_state::Status, + state: Option, + conf: Config, +) { let db = get_satp_requests_states_local_db(conf); let target: RequestState = RequestState { status: new_status as i32, @@ -241,9 +305,11 @@ pub fn update_request_state_in_local_satp_db(request_id: String, new_status: req println!("{:?}\n", db.get::(request_id).unwrap()) } -pub fn get_requesting_relay_host_and_port(transfer_commence_request: TransferCommenceRequest) -> (String, String) { - // TODO - return ("localhost".to_string(), "9085".to_string()) +pub fn get_requesting_relay_host_and_port( + transfer_commence_request: TransferCommenceRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); } pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { @@ -260,11 +326,16 @@ pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (relay_tls, relay_tlsca_cert_path) } -fn create_client_address (relay_host: String, relay_port: String) -> String { +fn create_client_address(relay_host: String, relay_port: String) -> String { return format!("http://{}:{}", relay_host, relay_port); } -pub async fn create_satp_client(relay_host: String, relay_port: String, use_tls: bool, tlsca_cert_path: String) -> Result, Box> { +pub async fn create_satp_client( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, +) -> Result, Box> { let client_addr = create_client_address(relay_host.clone(), relay_port.clone()); let satp_client; if use_tls { @@ -285,4 +356,4 @@ pub async fn create_satp_client(relay_host: String, relay_port: String, use_tls: satp_client = SatpClient::connect(client_addr).await?; } return Ok(satp_client); -} \ No newline at end of file +} diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 9f84c5dad4..2a0cdcbce3 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,16 +1,24 @@ // Internal generated modules use weaverpb::common::ack::{ack, Ack}; use weaverpb::relay::satp::satp_server::Satp; -use weaverpb::relay::satp::{TransferCommenceRequest, CommenceResponseRequest, LockAssertionRequest, LockAssertionReceiptRequest}; +use weaverpb::relay::satp::{ + CommenceResponseRequest, LockAssertionReceiptRequest, LockAssertionRequest, + TransferCommenceRequest, +}; // Internal modules use crate::error::Error; -use crate::services::satp_helper::{log_request_in_remote_sapt_db, log_request_in_local_sapt_db, create_ack_error_message}; +use crate::services::satp_helper::{ + create_ack_error_message, log_request_in_local_sapt_db, log_request_in_remote_sapt_db, +}; // external modules +use super::satp_helper::{ + create_commence_response_request, get_relay_params, get_requesting_relay_host_and_port, + spawn_send_commence_response_request, +}; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; -use super::satp_helper::{create_commence_response_request, get_requesting_relay_host_and_port, get_relay_params, spawn_send_commence_response_request}; #[derive(Debug, Default)] pub struct SatpService { @@ -21,13 +29,17 @@ pub struct SatpService { /// communication of the asset transfer protocol SATP between two gateways. #[tonic::async_trait] impl Satp for SatpService { - /// transfer_commence is run on the receiver gateway to allow the sender gateway to signal to the + /// transfer_commence is run on the receiver gateway to allow the sender gateway to signal to the /// receiver gateway that it is ready to start the transfer of the digital asset async fn transfer_commence( &self, - request: Request + request: Request, ) -> Result, Status> { - println!("Got a TransferCommenceRequest from {:?} - {:?}", request.remote_addr(), request); + println!( + "Got a TransferCommenceRequest from {:?} - {:?}", + request.remote_addr(), + request + ); let transfer_commence_request = request.into_inner().clone(); let request_id = transfer_commence_request.session_id.to_string(); @@ -36,10 +48,12 @@ impl Satp for SatpService { match log_request_in_remote_sapt_db(&request_id, &transfer_commence_request, conf.clone()) { Ok(_) => { println!("Successfully stored TransferCommenceRequest in remote satp_db with request_id: {}", request_id); - }, + } Err(e) => { // Internal failure of sled. Send Error response - let error_message = "Error storing TransferCommenceRequest in remote satp_db for request_id".to_string(); + let error_message = + "Error storing TransferCommenceRequest in remote satp_db for request_id" + .to_string(); let reply = create_ack_error_message(request_id, error_message, e); return reply; } @@ -48,7 +62,10 @@ impl Satp for SatpService { match transfer_commence_helper(transfer_commence_request, conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); - println!("Sending Ack of transfer commence request back: {:?}\n", reply); + println!( + "Sending Ack of transfer commence request back: {:?}\n", + reply + ); reply } Err(e) => { @@ -61,7 +78,7 @@ impl Satp for SatpService { async fn commence_response( &self, - request: Request + request: Request, ) -> Result, Status> { println!( "Got a commence response request from {:?} - {:?}", @@ -74,74 +91,63 @@ impl Satp for SatpService { let conf = self.config_lock.read().await; // TODO refactor - let request_logged: Result, Error> = log_request_in_local_sapt_db(&request_id, &commence_response_request, conf.clone()); + let request_logged: Result, Error> = + log_request_in_local_sapt_db(&request_id, &commence_response_request, conf.clone()); match request_logged { - Ok(_) => println!( - "Successfully stored CommenceResponseRequest in local satp_db with request_id: {}", - request_id - ), + Ok(_) => { + println!("Successfully stored CommenceResponseRequest in local satp_db with request_id: {}", request_id) + } Err(e) => { // Internal failure of sled. Send Error response - println!( - "Error storing CommenceResponseRequest in local satp_db for request_id: {}", - request_id - ); - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: request_id, - message: format!("Error storing CommenceResponseRequest in local satp_db {:?}", e), - })); - println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); + let error_message = + "Error storing CommenceResponseRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); return reply; } } - let reply = Ok( - Response::new(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error: Not implemented yet."), - }) - ); + + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: Not implemented yet."), + })); println!("Sending back Ack: {:?}\n", reply); reply } async fn lock_assertion( &self, - request: Request + request: Request, ) -> Result, Status> { println!( "Got a lock assertion request from {:?} - {:?}", request.remote_addr(), request ); - let reply = Ok( - Response::new(Ack { - status: ack::Status::Error as i32, - request_id: "xxxxxxxxx".to_string(), - message: format!("Error: Not implemented yet."), - }) - ); + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: "xxxxxxxxx".to_string(), + message: format!("Error: Not implemented yet."), + })); println!("Sending back Ack: {:?}\n", reply); reply } async fn lock_assertion_receipt( &self, - request: Request + request: Request, ) -> Result, Status> { println!( "Got a lock assertion receipt request from {:?} - {:?}", request.remote_addr(), request ); - let reply = Ok( - Response::new(Ack { - status: ack::Status::Error as i32, - request_id: "xxxxxxxxx".to_string(), - message: format!("Error: Not implemented yet."), - }) - ); + let reply = Ok(Response::new(Ack { + status: ack::Status::Error as i32, + request_id: "xxxxxxxxx".to_string(), + message: format!("Error: Not implemented yet."), + })); println!("Sending back Ack: {:?}\n", reply); reply } @@ -151,12 +157,11 @@ impl Satp for SatpService { /// requested from the sender gateway pub fn transfer_commence_helper( transfer_commence_request: TransferCommenceRequest, - conf: config::Config + conf: config::Config, ) -> Result { - let request_id = transfer_commence_request.session_id.to_string(); let is_valid_request = check_transfer_commence_request(transfer_commence_request.clone()); - + if is_valid_request { println!("The transfer commence request is valid\n"); match send_commence_response_helper(transfer_commence_request, conf) { @@ -167,7 +172,6 @@ pub fn transfer_commence_helper( reply } Err(e) => { - println!("Transfer commence request failed."); return Ok(Ack { status: ack::Status::Error as i32, request_id: request_id.to_string(), @@ -180,20 +184,25 @@ pub fn transfer_commence_helper( return Ok(Ack { status: ack::Status::Error as i32, request_id: request_id.to_string(), - message: "Invalid transfer commence request".to_string(), + message: "Error: The transfer commence request is invalid".to_string(), }); } } fn send_commence_response_helper( transfer_commence_request: TransferCommenceRequest, - conf: config::Config + conf: config::Config, ) -> Result { - let request_id = &transfer_commence_request.session_id.to_string(); - let (requesting_relay_host, requesting_relay_port) = get_requesting_relay_host_and_port(transfer_commence_request.clone()); - let (use_tls, relay_tlsca_cert_path) = get_relay_params(requesting_relay_host.clone(), requesting_relay_port.clone(), conf.clone()); - let commence_response_request = create_commence_response_request(transfer_commence_request.clone()); + let (requesting_relay_host, requesting_relay_port) = + get_requesting_relay_host_and_port(transfer_commence_request.clone()); + let (use_tls, relay_tlsca_cert_path) = get_relay_params( + requesting_relay_host.clone(), + requesting_relay_port.clone(), + conf.clone(), + ); + let commence_response_request = + create_commence_response_request(transfer_commence_request.clone()); spawn_send_commence_response_request( commence_response_request, @@ -201,7 +210,7 @@ fn send_commence_response_helper( requesting_relay_port, use_tls, relay_tlsca_cert_path, - conf + conf, ); let reply = Ack { status: ack::Status::Ok as i32, @@ -214,4 +223,4 @@ fn send_commence_response_helper( fn check_transfer_commence_request(transfer_commence_request: TransferCommenceRequest) -> bool { //TODO true -} \ No newline at end of file +} From 0449cd806d1ba84c0b60d60a82a38931476aa478 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 3 Jul 2023 13:37:08 +0100 Subject: [PATCH 10/59] initial commit --- .../protos-rs/pkg/src/generated/relay.satp.rs | 32 ++-- weaver/common/protos/relay/satp.proto | 6 +- weaver/core/relay/config/Corda_Relay.toml | 5 +- weaver/core/relay/config/Corda_Relay2.toml | 3 +- weaver/core/relay/config/Dummy_Relay.toml | 5 +- weaver/core/relay/config/Dummy_Relay_tls.toml | 3 +- weaver/core/relay/config/Fabric_Relay.toml | 3 +- weaver/core/relay/config/Fabric_Relay2.toml | 3 +- weaver/core/relay/config/Settings.toml | 5 +- weaver/core/relay/src/services/constants.rs | 5 + weaver/core/relay/src/services/mod.rs | 1 + weaver/core/relay/src/services/satp_helper.rs | 135 ++++++++++++---- .../core/relay/src/services/satp_service.rs | 144 ++++++++++++++---- 13 files changed, 251 insertions(+), 99 deletions(-) create mode 100644 weaver/core/relay/src/services/constants.rs diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index fb265aa96e..6076a7957e 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -54,7 +54,7 @@ pub struct TransferCommenceRequest { #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct CommenceResponseRequest { +pub struct AckCommenceRequest { #[prost(string, tag = "1")] pub message_type: ::prost::alloc::string::String, #[prost(string, tag = "2")] @@ -213,11 +213,11 @@ pub mod satp_client { ); self.inner.unary(request.into_request(), path, codec).await } - /// The receiver gateway sends a CommenceResponse request to the sender gateway to indicate agreement + /// The receiver gateway sends a AckCommence request to the sender gateway to indicate agreement /// to proceed with the asset transfe - pub async fn commence_response( + pub async fn ack_commence( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> Result< tonic::Response, tonic::Status, @@ -233,7 +233,7 @@ pub mod satp_client { })?; let codec = tonic::codec::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/relay.satp.SATP/CommenceResponse", + "/relay.satp.SATP/AckCommence", ); self.inner.unary(request.into_request(), path, codec).await } @@ -304,11 +304,11 @@ pub mod satp_server { tonic::Response, tonic::Status, >; - /// The receiver gateway sends a CommenceResponse request to the sender gateway to indicate agreement + /// The receiver gateway sends a AckCommence request to the sender gateway to indicate agreement /// to proceed with the asset transfe - async fn commence_response( + async fn ack_commence( &self, - request: tonic::Request, + request: tonic::Request, ) -> Result< tonic::Response, tonic::Status, @@ -432,13 +432,11 @@ pub mod satp_server { }; Box::pin(fut) } - "/relay.satp.SATP/CommenceResponse" => { + "/relay.satp.SATP/AckCommence" => { #[allow(non_camel_case_types)] - struct CommenceResponseSvc(pub Arc); - impl< - T: Satp, - > tonic::server::UnaryService - for CommenceResponseSvc { + struct AckCommenceSvc(pub Arc); + impl tonic::server::UnaryService + for AckCommenceSvc { type Response = super::super::super::common::ack::Ack; type Future = BoxFuture< tonic::Response, @@ -446,11 +444,11 @@ pub mod satp_server { >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = self.0.clone(); let fut = async move { - (*inner).commence_response(request).await + (*inner).ack_commence(request).await }; Box::pin(fut) } @@ -460,7 +458,7 @@ pub mod satp_server { let inner = self.inner.clone(); let fut = async move { let inner = inner.0; - let method = CommenceResponseSvc(inner); + let method = AckCommenceSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( diff --git a/weaver/common/protos/relay/satp.proto b/weaver/common/protos/relay/satp.proto index e4df80f997..d2ccdfd561 100644 --- a/weaver/common/protos/relay/satp.proto +++ b/weaver/common/protos/relay/satp.proto @@ -16,9 +16,9 @@ service SATP { // that the it is ready to start the transfer of the digital asset rpc TransferCommence(TransferCommenceRequest) returns (common.ack.Ack) {}; - // The receiver gateway sends a CommenceResponse request to the sender gateway to indicate agreement + // The receiver gateway sends a AckCommence request to the sender gateway to indicate agreement // to proceed with the asset transfe - rpc CommenceResponse(CommenceResponseRequest) returns (common.ack.Ack) {}; + rpc AckCommence(AckCommenceRequest) returns (common.ack.Ack) {}; // The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway // declaring that the asset in question has been locked or escrowed by the sender gateway in @@ -58,7 +58,7 @@ message TransferCommenceRequest { // AssetTransferInitializationClaims asset_transfer_initialization_claims = 10; } -message CommenceResponseRequest { +message AckCommenceRequest { string message_type = 1; string session_id = 2; string transfer_context_id = 3; diff --git a/weaver/core/relay/config/Corda_Relay.toml b/weaver/core/relay/config/Corda_Relay.toml index 08fa0b78af..3d41dfc2b6 100644 --- a/weaver/core/relay/config/Corda_Relay.toml +++ b/weaver/core/relay/config/Corda_Relay.toml @@ -3,12 +3,9 @@ port="9081" host="localhost" hostname="localhost" db_path="db/Corda_Relay/requests" -db_satp_requests_path="db/Corda_Relay/satp/requests" -db_satp_requests_states_path="db/Corda_Relay/satp/requests_states" # This will be replaced by the task queue. remote_db_path="db/Corda_Relay/remote_request" -remote_db_satp_requests_path="db/Corda_Relay/satp/remote_requests_states" -remote_db_satp_requests_states_path="db/Corda_Relay/satp/requests_states" +db_satp_path="db/Corda_Relay" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Corda_Relay2.toml b/weaver/core/relay/config/Corda_Relay2.toml index 1a53a655df..172dfa4c91 100644 --- a/weaver/core/relay/config/Corda_Relay2.toml +++ b/weaver/core/relay/config/Corda_Relay2.toml @@ -3,10 +3,9 @@ port="9082" host="localhost" hostname="localhost" db_path="db/Corda_Relay2/requests" -db_satp_path="db/Corda_Relay2/satp/requests" # This will be replaced by the task queue. remote_db_path="db/Corda_Relay2/remote_request" -remote_db_satp_path="db/Corda_Relay2/satp/remote_request" +db_satp_path="db/Corda_Relay2" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Dummy_Relay.toml b/weaver/core/relay/config/Dummy_Relay.toml index 48d5e858c1..125d18af27 100644 --- a/weaver/core/relay/config/Dummy_Relay.toml +++ b/weaver/core/relay/config/Dummy_Relay.toml @@ -2,12 +2,9 @@ name = "Dummy_Relay" port="9085" hostname="localhost" db_path="db/Dummy_Relay/requests" -db_satp_requests_path="db/Dummy_Relay/satp/requests" -db_satp_requests_states_path="db/Dummy_Relay/satp/requests_states" # This will be replaced by the task queue. remote_db_path="db/Dummy_Relay/remote_request" -remote_db_satp_requests_path="db/Dummy_Relay/satp/remote_requests_states" -remote_db_satp_requests_states_path="db/Dummy_Relay/satp/requests_states" +db_satp_path="db/Dummy_Relay" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Dummy_Relay_tls.toml b/weaver/core/relay/config/Dummy_Relay_tls.toml index fb466fb4e2..fd191ff93f 100644 --- a/weaver/core/relay/config/Dummy_Relay_tls.toml +++ b/weaver/core/relay/config/Dummy_Relay_tls.toml @@ -2,10 +2,9 @@ name = "Dummy_Relay" port="9085" hostname="localhost" db_path="db/Dummy_Relay_tls/requests" -db_satp_path="db/Dummy_Relay_tls/satp/requests" # This will be replaced by the task queue. remote_db_path="db/Dummy_Relay_tls/remote_request" -remote_db_satp_path="db/Dummy_Relay_tls/satp/remote_request" +db_satp_path="db/Dummy_Relay_tls" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Fabric_Relay.toml b/weaver/core/relay/config/Fabric_Relay.toml index b6c36790c6..aabe72b2a8 100644 --- a/weaver/core/relay/config/Fabric_Relay.toml +++ b/weaver/core/relay/config/Fabric_Relay.toml @@ -2,10 +2,9 @@ name = "Fabric_Relay" port="9080" hostname="localhost" db_path="db/Fabric_Relay/requests" -db_satp_path="db/Fabric_Relay/satp/requests" # This will be replaced by the task queue. remote_db_path="db/Fabric_Relay/remote_request" -remote_db_satp_path="db/Fabric_Relay/satp/remote_request" +db_satp_path="db/Fabric_Relay" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Fabric_Relay2.toml b/weaver/core/relay/config/Fabric_Relay2.toml index bdb5528478..c7449f72e1 100644 --- a/weaver/core/relay/config/Fabric_Relay2.toml +++ b/weaver/core/relay/config/Fabric_Relay2.toml @@ -2,10 +2,9 @@ name = "Fabric_Relay2" port="9083" hostname="localhost" db_path="db/Fabric_Relay2/requests" -db_satp_path="db/Fabric_Relay2/satp/requests" # This will be replaced by the task queue. remote_db_path="db/Fabric_Relay2/remote_request" -remote_db_satp_path="db/Fabric_Relay2/satp/remote_request" +db_satp_path="db/Fabric_Relay2" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/config/Settings.toml b/weaver/core/relay/config/Settings.toml index 23185d8e6d..6299bce119 100644 --- a/weaver/core/relay/config/Settings.toml +++ b/weaver/core/relay/config/Settings.toml @@ -2,12 +2,9 @@ name = "Fabric_Relay" port="9080" hostname="localhost" db_path="db/requests" -db_satp_requests_path="db/satp/requests" -db_satp_requests_states_path="db/satp/requests_states" # This will be replaced by the task queue. remote_db_path="db/remote_requests" -remote_db_satp_requests_path="db/satp/remote_requests_states" -remote_db_satp_requests_states_path="db/satp/requests_states" +db_satp_path="db" # max retries opening sled db if it is locked db_open_max_retries=500 # retry back off time in ms if sled db is locked diff --git a/weaver/core/relay/src/services/constants.rs b/weaver/core/relay/src/services/constants.rs new file mode 100644 index 0000000000..fc22e7bcc7 --- /dev/null +++ b/weaver/core/relay/src/services/constants.rs @@ -0,0 +1,5 @@ +pub static SATP_DB_PATH: &str = "db_satp_path"; +pub static SATP_REQUESTS_DB_PATH: &str = "/satp/requests"; +pub static SATP_REQUESTS_STATES_DB_PATH: &str = "/satp/requests_states"; +pub static SATP_REMOTE_REQUESTS_DB_PATH: &str = "/satp/remote_requests"; +pub static SATP_REMOTE_REQUESTS_STATES_DB_PATH: &str = "/satp/remote_requests_states"; \ No newline at end of file diff --git a/weaver/core/relay/src/services/mod.rs b/weaver/core/relay/src/services/mod.rs index 98d370570c..8df9186302 100644 --- a/weaver/core/relay/src/services/mod.rs +++ b/weaver/core/relay/src/services/mod.rs @@ -6,3 +6,4 @@ pub mod event_publish_service; pub mod helpers; pub mod satp_helper; pub mod types; +pub mod constants; diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 22ec333744..bf8ca3710b 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -8,12 +8,14 @@ use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::state::{request_state, RequestState}; use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; -use weaverpb::relay::satp::{CommenceResponseRequest, TransferCommenceRequest}; +use weaverpb::relay::satp::{AckCommenceRequest, TransferCommenceRequest, LockAssertionRequest}; use crate::db::Database; use crate::error::{self, Error}; use crate::relay_proto::LocationSegment; +use super::constants::{SATP_DB_PATH, SATP_REQUESTS_DB_PATH, SATP_REMOTE_REQUESTS_DB_PATH, SATP_REMOTE_REQUESTS_STATES_DB_PATH, SATP_REQUESTS_STATES_DB_PATH}; + // Sends a request to the receiving gateway pub fn spawn_send_transfer_commence_request( conf: config::Config, @@ -25,7 +27,7 @@ pub fn spawn_send_transfer_commence_request( "Sending transfer commence request to receiver gateway: {:?}:{:?}", receiver_relay_host, receiver_relay_port ); - // Spawning new thread to make the asset_transfer_call to receiver gateway + // Spawning new thread to make the call_asset_transfer to receiver gateway tokio::spawn(async move { let (use_tls, relay_tlsca_cert_path) = get_relay_params( receiver_relay_host.clone(), @@ -33,7 +35,7 @@ pub fn spawn_send_transfer_commence_request( conf.clone(), ); let request_id = transfer_commence_request.session_id.to_string(); - let result = transfer_commence_call( + let result = call_transfer_commence( receiver_relay_host, receiver_relay_port, use_tls, @@ -48,8 +50,8 @@ pub fn spawn_send_transfer_commence_request( }); } -pub fn spawn_send_commence_response_request( - commence_response_request: CommenceResponseRequest, +pub fn spawn_send_ack_commence_request( + ack_commence_request: AckCommenceRequest, requesting_relay_host: String, requesting_relay_port: String, use_tls: bool, @@ -59,26 +61,60 @@ pub fn spawn_send_commence_response_request( tokio::spawn(async move { println!( "Sending commence response back to sending gateway: Request ID = {:?}", - commence_response_request.session_id + ack_commence_request.session_id + ); + let result = call_ack_commence( + requesting_relay_host, + requesting_relay_port, + use_tls, + relay_tlsca_cert_path.to_string(), + ack_commence_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = ack_commence_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_perform_lock_request( + lock_assertion_request: LockAssertionRequest, + requesting_relay_host: String, + requesting_relay_port: String, + use_tls: bool, + relay_tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + println!( + "Locking the asset of the lock assertion request {:?}", + lock_assertion_request ); - let result = commence_response_call( + // TODO + // Call the driver to check the asset status + // Subscribe to the status event + // Once the asset is locked, call the lock_assertion endpoint + // log the results + let result = call_lock_assertion( requesting_relay_host, requesting_relay_port, use_tls, relay_tlsca_cert_path.to_string(), - commence_response_request.clone(), + lock_assertion_request.clone(), ) .await; println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - let request_id = commence_response_request.session_id.to_string(); + let request_id = lock_assertion_request.session_id.to_string(); log_request_result_in_local_satp_db(&request_id, result, conf); }); } // Call the transfer_commence endpoint on the receiver gateway -pub async fn transfer_commence_call( +pub async fn call_transfer_commence( relay_host: String, relay_port: String, use_tls: bool, @@ -97,22 +133,42 @@ pub async fn transfer_commence_call( Ok(response) } -// Call the commence_response endpoint on the sending gateway -pub async fn commence_response_call( +// Call the ack_commence endpoint on the sending gateway +pub async fn call_ack_commence( relay_host: String, relay_port: String, use_tls: bool, tlsca_cert_path: String, - commence_response_request: CommenceResponseRequest, + ack_commence_request: AckCommenceRequest, ) -> Result, Box> { let mut satp_client: SatpClient = create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; println!( "Sending the commence response request: {:?}", - commence_response_request.clone() + ack_commence_request.clone() + ); + let response = satp_client + .ack_commence(ack_commence_request.clone()) + .await?; + Ok(response) +} + +// Call the lock_assertion endpoint on the sending gateway +pub async fn call_lock_assertion( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + lock_assertion_request: LockAssertionRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the lock assertion request: {:?}", + lock_assertion_request.clone() ); let response = satp_client - .commence_response(commence_response_request.clone()) + .lock_assertion(lock_assertion_request.clone()) .await?; Ok(response) } @@ -196,10 +252,10 @@ pub fn derive_transfer_commence_request( return transfer_commence_request; } -pub fn create_commence_response_request( +pub fn create_ack_commence_request( transfer_commence_request: TransferCommenceRequest, -) -> CommenceResponseRequest { - let commence_response_request = CommenceResponseRequest { +) -> AckCommenceRequest { + let ack_commence_request = AckCommenceRequest { message_type: "message_type1".to_string(), session_id: "session_id1".to_string(), transfer_context_id: "transfer_context_id1".to_string(), @@ -209,31 +265,49 @@ pub fn create_commence_response_request( server_transfer_number: "server_transfer_number1".to_string(), server_signature: "server_signature1".to_string(), }; + return ack_commence_request; +} - return commence_response_request; +pub fn create_lock_assertion_request( + ack_commence_request: AckCommenceRequest, +) -> LockAssertionRequest { + let lock_assertion_request = LockAssertionRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + hash_prev_message: "hash_prev_message1".to_string(), + lock_assertion_claim: "lock_assertion_claim1".to_string(), + lock_assertion_claim_format: "lock_assertion_claim_format1".to_string(), + lock_assertion_expiration: "lock_assertion_expiration".to_string(), + client_transfer_number: "client_transfer_number1".to_string(), + client_signature: "client_signature1".to_string(), + }; + return lock_assertion_request; } pub fn get_satp_requests_local_db(conf: Config) -> Database { let db = Database { - db_path: conf.get_str("db_satp_requests_path").unwrap(), + db_path: format!("{}{}", conf.get_str(SATP_DB_PATH).unwrap(), SATP_REQUESTS_DB_PATH), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, }; return db; } -pub fn get_satp_requests_states_local_db(conf: Config) -> Database { +pub fn get_satp_requests_remote_db(conf: Config) -> Database { let db = Database { - db_path: conf.get_str("db_satp_requests_states_path").unwrap(), + db_path: format!("{}{}", conf.get_str(SATP_DB_PATH).unwrap(), SATP_REMOTE_REQUESTS_DB_PATH), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, }; return db; } -pub fn get_satp_requests_remote_db(conf: Config) -> Database { +pub fn get_satp_requests_states_local_db(conf: Config) -> Database { let db = Database { - db_path: conf.get_str("remote_db_satp_requests_path").unwrap(), + db_path: format!("{}{}", conf.get_str(SATP_DB_PATH).unwrap(), SATP_REQUESTS_STATES_DB_PATH), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, }; @@ -242,7 +316,7 @@ pub fn get_satp_requests_remote_db(conf: Config) -> Database { pub fn get_satp_requests_states_remote_db(conf: Config) -> Database { let db = Database { - db_path: conf.get_str("remote_db_satp_requests_states_path").unwrap(), + db_path: format!("{}{}", conf.get_str(SATP_DB_PATH).unwrap(), SATP_REMOTE_REQUESTS_STATES_DB_PATH), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, }; @@ -305,13 +379,22 @@ pub fn update_request_state_in_local_satp_db( println!("{:?}\n", db.get::(request_id).unwrap()) } -pub fn get_requesting_relay_host_and_port( +// Get the requesting relay host and port +pub fn get_relay_from_transfer_commence( transfer_commence_request: TransferCommenceRequest, ) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } +// Get the requesting relay host and port +pub fn get_relay_from_ack_commence( + ack_commence_request: AckCommenceRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 2a0cdcbce3..3c5be005a1 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -2,8 +2,7 @@ use weaverpb::common::ack::{ack, Ack}; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{ - CommenceResponseRequest, LockAssertionReceiptRequest, LockAssertionRequest, - TransferCommenceRequest, + AckCommenceRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, }; // Internal modules @@ -14,8 +13,9 @@ use crate::services::satp_helper::{ // external modules use super::satp_helper::{ - create_commence_response_request, get_relay_params, get_requesting_relay_host_and_port, - spawn_send_commence_response_request, + create_ack_commence_request, create_lock_assertion_request, get_relay_from_ack_commence, + get_relay_from_transfer_commence, get_relay_params, spawn_send_ack_commence_request, + spawn_send_perform_lock_request, }; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; @@ -59,7 +59,7 @@ impl Satp for SatpService { } } - match transfer_commence_helper(transfer_commence_request, conf.clone()) { + match process_transfer_commence_request(transfer_commence_request, conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!( @@ -76,44 +76,51 @@ impl Satp for SatpService { } } - async fn commence_response( + async fn ack_commence( &self, - request: Request, + request: Request, ) -> Result, Status> { println!( - "Got a commence response request from {:?} - {:?}", + "Got an ack commence request from {:?} - {:?}", request.remote_addr(), request ); - let commence_response_request = request.into_inner().clone(); - let request_id = commence_response_request.session_id.to_string(); + let ack_commence_request = request.into_inner().clone(); + let request_id = ack_commence_request.session_id.to_string(); let conf = self.config_lock.read().await; // TODO refactor let request_logged: Result, Error> = - log_request_in_local_sapt_db(&request_id, &commence_response_request, conf.clone()); + log_request_in_local_sapt_db(&request_id, &ack_commence_request, conf.clone()); match request_logged { Ok(_) => { - println!("Successfully stored CommenceResponseRequest in local satp_db with request_id: {}", request_id) + println!( + "Successfully stored AckCommenceRequest in local satp_db with request_id: {}", + request_id + ) } Err(e) => { // Internal failure of sled. Send Error response let error_message = - "Error storing CommenceResponseRequest in local satp_db for request_id" - .to_string(); + "Error storing AckCommenceRequest in local satp_db for request_id".to_string(); let reply = create_ack_error_message(request_id, error_message, e); return reply; } } - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error: Not implemented yet."), - })); - println!("Sending back Ack: {:?}\n", reply); - reply + match process_ack_commence_request(ack_commence_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!("Sending Ack of ack commence request back: {:?}\n", reply); + reply + } + Err(e) => { + let error_message = "Ack commence failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } } async fn lock_assertion( @@ -153,18 +160,18 @@ impl Satp for SatpService { } } -/// transfer_commence_helper is run on the receiver gateway to initiate asset transfer protocol that was +/// process_transfer_commence_request is run on the receiver gateway to initiate asset transfer protocol that was /// requested from the sender gateway -pub fn transfer_commence_helper( +pub fn process_transfer_commence_request( transfer_commence_request: TransferCommenceRequest, conf: config::Config, ) -> Result { let request_id = transfer_commence_request.session_id.to_string(); - let is_valid_request = check_transfer_commence_request(transfer_commence_request.clone()); + let is_valid_request = is_valid_transfer_commence_request(transfer_commence_request.clone()); if is_valid_request { println!("The transfer commence request is valid\n"); - match send_commence_response_helper(transfer_commence_request, conf) { + match send_ack_commence_request(transfer_commence_request, conf) { Ok(ack) => { println!("Ack transfer commence request."); let reply = Ok(ack); @@ -175,7 +182,7 @@ pub fn transfer_commence_helper( return Ok(Ack { status: ack::Status::Error as i32, request_id: request_id.to_string(), - message: format!("Error: Transfer commence request failed. {:?}", e), + message: format!("Error: Ack commence request failed. {:?}", e), }); } } @@ -189,23 +196,59 @@ pub fn transfer_commence_helper( } } -fn send_commence_response_helper( +/// process_ack_commence_request is invoked by the receiver gateway to ack the transfer commence request +/// requested ed by the sender gateway +pub fn process_ack_commence_request( + ack_commence_request: AckCommenceRequest, + conf: config::Config, +) -> Result { + let request_id = ack_commence_request.session_id.to_string(); + let is_valid_request = is_valid_ack_commence_request(ack_commence_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The ack commence request is valid\n"); + match send_perform_lock_request(ack_commence_request, conf) { + Ok(ack) => { + println!("Ack ack commence request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: perform lock request failed. {:?}", e), + }); + } + } + } else { + println!("The ack commence request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The ack commence request is invalid".to_string(), + }); + } +} + +fn send_ack_commence_request( transfer_commence_request: TransferCommenceRequest, conf: config::Config, ) -> Result { let request_id = &transfer_commence_request.session_id.to_string(); let (requesting_relay_host, requesting_relay_port) = - get_requesting_relay_host_and_port(transfer_commence_request.clone()); + get_relay_from_transfer_commence(transfer_commence_request.clone()); let (use_tls, relay_tlsca_cert_path) = get_relay_params( requesting_relay_host.clone(), requesting_relay_port.clone(), conf.clone(), ); - let commence_response_request = - create_commence_response_request(transfer_commence_request.clone()); + let ack_commence_request = create_ack_commence_request(transfer_commence_request.clone()); - spawn_send_commence_response_request( - commence_response_request, + spawn_send_ack_commence_request( + ack_commence_request, requesting_relay_host, requesting_relay_port, use_tls, @@ -220,7 +263,42 @@ fn send_commence_response_helper( return Ok(reply); } -fn check_transfer_commence_request(transfer_commence_request: TransferCommenceRequest) -> bool { +fn send_perform_lock_request( + ack_commence_request: AckCommenceRequest, + conf: config::Config, +) -> Result { + let request_id = &ack_commence_request.session_id.to_string(); + let (requesting_relay_host, requesting_relay_port) = + get_relay_from_ack_commence(ack_commence_request.clone()); + let (use_tls, relay_tlsca_cert_path) = get_relay_params( + requesting_relay_host.clone(), + requesting_relay_port.clone(), + conf.clone(), + ); + let perfrom_lock_request = create_lock_assertion_request(ack_commence_request.clone()); + + spawn_send_perform_lock_request( + perfrom_lock_request, + requesting_relay_host, + requesting_relay_port, + use_tls, + relay_tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the ack commence request".to_string(), + }; + return Ok(reply); +} + +fn is_valid_transfer_commence_request(transfer_commence_request: TransferCommenceRequest) -> bool { + //TODO + true +} + +fn is_valid_ack_commence_request(ack_commence_request: AckCommenceRequest) -> bool { //TODO true } From a63d7d6652522f314f0e4b25242299b5cac7384a Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 31 Jul 2023 09:41:17 +0100 Subject: [PATCH 11/59] initial commit --- weaver/core/relay/src/services/network_service.rs | 8 ++++---- weaver/core/relay/src/services/satp_helper.rs | 8 ++++---- weaver/core/relay/src/services/satp_service.rs | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 8300e439b5..ededc1b6e3 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -23,8 +23,8 @@ use crate::services::helpers::{ update_event_subscription_status, }; use crate::services::satp_helper::{ - derive_transfer_commence_request, log_request_in_local_sapt_db, - log_request_state_in_local_sapt_db, spawn_send_transfer_commence_request, + derive_transfer_commence_request, log_request_in_local_satp_db, + log_request_state_in_local_satp_db, spawn_send_transfer_commence_request, }; // External modules @@ -531,7 +531,7 @@ impl Network for NetworkService { let request_id = transfer_commence_request.session_id.to_string(); // TODO refactor let request_logged: Result, crate::error::Error> = - log_request_in_local_sapt_db(&request_id, &network_asset_transfer, conf.clone()); + log_request_in_local_satp_db(&request_id, &network_asset_transfer, conf.clone()); match request_logged { Ok(_) => println!( "Successfully stored NetworkAssetTransfer in local satp_db with request_id: {}", @@ -563,7 +563,7 @@ impl Network for NetworkService { state: None, }; let request_state_logged: Result, crate::error::Error> = - log_request_state_in_local_sapt_db(&request_id, &target, conf.clone()); + log_request_state_in_local_satp_db(&request_id, &target, conf.clone()); match request_state_logged { Ok(_) => println!( "Successfully stored RequestState in local satp_db with request_id: {}", diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index bf8ca3710b..400d2e6b49 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -323,7 +323,7 @@ pub fn get_satp_requests_states_remote_db(conf: Config) -> Database { return db; } -pub fn log_request_state_in_local_sapt_db( +pub fn log_request_state_in_local_satp_db( request_id: &String, target: &RequestState, conf: Config, @@ -332,7 +332,7 @@ pub fn log_request_state_in_local_sapt_db( return db.set(&request_id, &target); } -pub fn log_request_in_local_sapt_db( +pub fn log_request_in_local_satp_db( request_id: &String, value: T, conf: Config, @@ -341,7 +341,7 @@ pub fn log_request_in_local_sapt_db( return db.set(&request_id, &value); } -pub fn log_request_in_remote_sapt_db( +pub fn log_request_in_remote_satp_db( request_id: &String, value: T, conf: Config, @@ -350,7 +350,7 @@ pub fn log_request_in_remote_sapt_db( return db.set(&request_id, &value); } -pub fn get_request_from_remote_sapt_db( +pub fn get_request_from_remote_satp_db( request_id: &String, conf: Config, ) -> Result { diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 3c5be005a1..618d1aac01 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -8,7 +8,7 @@ use weaverpb::relay::satp::{ // Internal modules use crate::error::Error; use crate::services::satp_helper::{ - create_ack_error_message, log_request_in_local_sapt_db, log_request_in_remote_sapt_db, + create_ack_error_message, log_request_in_local_satp_db, log_request_in_remote_satp_db, }; // external modules @@ -45,7 +45,7 @@ impl Satp for SatpService { let request_id = transfer_commence_request.session_id.to_string(); let conf = self.config_lock.read().await; - match log_request_in_remote_sapt_db(&request_id, &transfer_commence_request, conf.clone()) { + match log_request_in_remote_satp_db(&request_id, &transfer_commence_request, conf.clone()) { Ok(_) => { println!("Successfully stored TransferCommenceRequest in remote satp_db with request_id: {}", request_id); } @@ -92,7 +92,7 @@ impl Satp for SatpService { // TODO refactor let request_logged: Result, Error> = - log_request_in_local_sapt_db(&request_id, &ack_commence_request, conf.clone()); + log_request_in_local_satp_db(&request_id, &ack_commence_request, conf.clone()); match request_logged { Ok(_) => { println!( From af47784b878779e838ea6129e0d4851322fc2a32 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 31 Jul 2023 09:48:45 +0100 Subject: [PATCH 12/59] initial commit --- ...sset-transfer.yaml => test_weaver-fabric-fabric-satp.yaml} | 0 weaver/core/relay/Cargo.toml | 4 ---- 2 files changed, 4 deletions(-) rename .github/workflows/{test_weaver-fabric-fabric-asset-transfer.yaml => test_weaver-fabric-fabric-satp.yaml} (100%) diff --git a/.github/workflows/test_weaver-fabric-fabric-asset-transfer.yaml b/.github/workflows/test_weaver-fabric-fabric-satp.yaml similarity index 100% rename from .github/workflows/test_weaver-fabric-fabric-asset-transfer.yaml rename to .github/workflows/test_weaver-fabric-fabric-satp.yaml diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index 8b3f812a97..123e42eec4 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -20,10 +20,6 @@ path = "src/satp_client.rs" name = "client-tls" path = "src/client_tls.rs" -[[bin]] -name = "satp-client" -path = "src/satp_client.rs" - [[bin]] name = "dummy-driver" path = "driver/driver.rs" From 98551d2ace4e2ee8056a624d07fa4a11c2dc4da1 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 1 Aug 2023 11:43:38 +0100 Subject: [PATCH 13/59] Implemented the two endpoints TransferProposalClaims and TransferProposalReceipt --- .../protos-rs/pkg/src/generated/relay.satp.rs | 204 ++++++++++- weaver/common/protos/relay/satp.proto | 58 ++- .../relay/src/services/network_service.rs | 30 +- weaver/core/relay/src/services/satp_helper.rs | 275 ++++++++++++-- .../core/relay/src/services/satp_service.rs | 335 ++++++++++++++++-- 5 files changed, 807 insertions(+), 95 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index 6076a7957e..0031a5dacd 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -1,30 +1,63 @@ #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct AssetTransferInitializationClaims { +pub struct TransferProposalClaimsRequest { #[prost(string, tag = "1")] - pub asset_asset_id: ::prost::alloc::string::String, + pub message_type: ::prost::alloc::string::String, #[prost(string, tag = "2")] - pub asset_profile_id: ::prost::alloc::string::String, + pub asset_asset_id: ::prost::alloc::string::String, #[prost(string, tag = "3")] - pub verified_originator_entity_id: ::prost::alloc::string::String, + pub asset_profile_id: ::prost::alloc::string::String, #[prost(string, tag = "4")] - pub verified_beneficiary_entity_id: ::prost::alloc::string::String, + pub verified_originator_entity_id: ::prost::alloc::string::String, #[prost(string, tag = "5")] - pub originator_pubkey: ::prost::alloc::string::String, + pub verified_beneficiary_entity_id: ::prost::alloc::string::String, #[prost(string, tag = "6")] - pub beneficiary_pubkey: ::prost::alloc::string::String, + pub originator_pubkey: ::prost::alloc::string::String, #[prost(string, tag = "7")] - pub sender_gateway_network_id: ::prost::alloc::string::String, + pub beneficiary_pubkey: ::prost::alloc::string::String, #[prost(string, tag = "8")] - pub recipient_gateway_network_id: ::prost::alloc::string::String, + pub sender_gateway_network_id: ::prost::alloc::string::String, #[prost(string, tag = "9")] - pub client_identity_pubkey: ::prost::alloc::string::String, + pub recipient_gateway_network_id: ::prost::alloc::string::String, #[prost(string, tag = "10")] - pub server_identity_pubkey: ::prost::alloc::string::String, + pub client_identity_pubkey: ::prost::alloc::string::String, #[prost(string, tag = "11")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "12")] pub sender_gateway_owner_id: ::prost::alloc::string::String, + #[prost(string, tag = "13")] + pub receiver_gateway_owner_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransferProposalReceiptRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub asset_asset_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub asset_profile_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub verified_originator_entity_id: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub verified_beneficiary_entity_id: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub originator_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub beneficiary_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub sender_gateway_network_id: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub recipient_gateway_network_id: ::prost::alloc::string::String, + #[prost(string, tag = "10")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "11")] + pub server_identity_pubkey: ::prost::alloc::string::String, #[prost(string, tag = "12")] + pub sender_gateway_owner_id: ::prost::alloc::string::String, + #[prost(string, tag = "13")] pub receiver_gateway_owner_id: ::prost::alloc::string::String, } #[derive(serde::Serialize, serde::Deserialize)] @@ -47,7 +80,6 @@ pub struct TransferCommenceRequest { pub hash_prev_message: ::prost::alloc::string::String, #[prost(string, tag = "8")] pub client_transfer_number: ::prost::alloc::string::String, - /// AssetTransferInitializationClaims asset_transfer_initialization_claims = 10; #[prost(string, tag = "9")] pub client_signature: ::prost::alloc::string::String, } @@ -189,6 +221,54 @@ pub mod satp_client { self.inner = self.inner.accept_compressed(encoding); self } + /// The sender gateway sends a TransferProposalClaims request to to initiate an asset transfer. + /// Depending on the proposal, multiple rounds of communication between the two gateways may happen. + pub async fn transfer_proposal_claims( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/TransferProposalClaims", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// The sender gateway sends a TransferProposalClaims request to signal to the receiver gateway + /// that the it is ready to start the transfer of the digital asset + pub async fn transfer_proposal_receipt( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/TransferProposalReceipt", + ); + self.inner.unary(request.into_request(), path, codec).await + } /// The sender gateway sends a TransferCommence request to signal to the receiver gateway /// that the it is ready to start the transfer of the digital asset pub async fn transfer_commence( @@ -295,6 +375,24 @@ pub mod satp_server { /// Generated trait containing gRPC methods that should be implemented for use with SatpServer. #[async_trait] pub trait Satp: Send + Sync + 'static { + /// The sender gateway sends a TransferProposalClaims request to to initiate an asset transfer. + /// Depending on the proposal, multiple rounds of communication between the two gateways may happen. + async fn transfer_proposal_claims( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// The sender gateway sends a TransferProposalClaims request to signal to the receiver gateway + /// that the it is ready to start the transfer of the digital asset + async fn transfer_proposal_receipt( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; /// The sender gateway sends a TransferCommence request to signal to the receiver gateway /// that the it is ready to start the transfer of the digital asset async fn transfer_commence( @@ -392,6 +490,88 @@ pub mod satp_server { fn call(&mut self, req: http::Request) -> Self::Future { let inner = self.inner.clone(); match req.uri().path() { + "/relay.satp.SATP/TransferProposalClaims" => { + #[allow(non_camel_case_types)] + struct TransferProposalClaimsSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for TransferProposalClaimsSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).transfer_proposal_claims(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = TransferProposalClaimsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/TransferProposalReceipt" => { + #[allow(non_camel_case_types)] + struct TransferProposalReceiptSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for TransferProposalReceiptSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::TransferProposalReceiptRequest, + >, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).transfer_proposal_receipt(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = TransferProposalReceiptSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/relay.satp.SATP/TransferCommence" => { #[allow(non_camel_case_types)] struct TransferCommenceSvc(pub Arc); diff --git a/weaver/common/protos/relay/satp.proto b/weaver/common/protos/relay/satp.proto index d2ccdfd561..66d2bf7073 100644 --- a/weaver/common/protos/relay/satp.proto +++ b/weaver/common/protos/relay/satp.proto @@ -10,7 +10,15 @@ option java_package = "org.hyperledger.cacti.weaver.protos.relay.datatransfer"; option go_package = "github.com/hyperledger/cacti/weaver/common/protos-go/v2/relay"; service SATP { - // Stage 2 endpoints + // Stage 1 endpoints + + // The sender gateway sends a TransferProposalClaims request to initiate an asset transfer. + // Depending on the proposal, multiple rounds of communication between the two gateways may happen. + rpc TransferProposalClaims(TransferProposalClaimsRequest) returns (common.ack.Ack) {}; + + // The sender gateway sends a TransferProposalClaims request to signal to the receiver gateway + // that the it is ready to start the transfer of the digital asset + rpc TransferProposalReceipt(TransferProposalReceiptRequest) returns (common.ack.Ack) {}; // The sender gateway sends a TransferCommence request to signal to the receiver gateway // that the it is ready to start the transfer of the digital asset @@ -20,9 +28,11 @@ service SATP { // to proceed with the asset transfe rpc AckCommence(AckCommenceRequest) returns (common.ack.Ack) {}; + // Stage 2 endpoints + // The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway // declaring that the asset in question has been locked or escrowed by the sender gateway in - // the origin network (e.g. to prevent double spending + // the origin network (e.g. to prevent double spending) rpc LockAssertion(LockAssertionRequest) returns (common.ack.Ack) {}; // The receiver gateway sends a LockAssertionReceipt request to the sender gateway to indicate acceptance @@ -30,19 +40,36 @@ service SATP { rpc LockAssertionReceipt(LockAssertionReceiptRequest) returns (common.ack.Ack) {}; } -message AssetTransferInitializationClaims { - string asset_asset_id = 1; - string asset_profile_id = 2; - string verified_originator_entity_id = 3; - string verified_beneficiary_entity_id = 4; - string originator_pubkey = 5; - string beneficiary_pubkey = 6; - string sender_gateway_network_id = 7; - string recipient_gateway_network_id = 8; - string client_identity_pubkey = 9; - string server_identity_pubkey = 10; - string sender_gateway_owner_id = 11; - string receiver_gateway_owner_id = 12; +message TransferProposalClaimsRequest { + string message_type = 1; + string asset_asset_id = 2; + string asset_profile_id = 3; + string verified_originator_entity_id = 4; + string verified_beneficiary_entity_id = 5; + string originator_pubkey = 6; + string beneficiary_pubkey = 7; + string sender_gateway_network_id = 8; + string recipient_gateway_network_id = 9; + string client_identity_pubkey = 10; + string server_identity_pubkey = 11; + string sender_gateway_owner_id = 12; + string receiver_gateway_owner_id = 13; +} + +message TransferProposalReceiptRequest { + string message_type = 1; + string asset_asset_id = 2; + string asset_profile_id = 3; + string verified_originator_entity_id = 4; + string verified_beneficiary_entity_id = 5; + string originator_pubkey = 6; + string beneficiary_pubkey = 7; + string sender_gateway_network_id = 8; + string recipient_gateway_network_id = 9; + string client_identity_pubkey = 10; + string server_identity_pubkey = 11; + string sender_gateway_owner_id = 12; + string receiver_gateway_owner_id = 13; } message TransferCommenceRequest { @@ -55,7 +82,6 @@ message TransferCommenceRequest { string hash_prev_message = 7; string client_transfer_number = 8; string client_signature = 9; - // AssetTransferInitializationClaims asset_transfer_initialization_claims = 10; } message AckCommenceRequest { diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index ededc1b6e3..10ae6a7c72 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -14,7 +14,7 @@ use weaverpb::networks::networks::{ }; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; -use weaverpb::relay::satp::TransferCommenceRequest; +use weaverpb::relay::satp::TransferProposalClaimsRequest; // Internal modules use crate::db::Database; use crate::services::helpers::{ @@ -23,8 +23,9 @@ use crate::services::helpers::{ update_event_subscription_status, }; use crate::services::satp_helper::{ - derive_transfer_commence_request, log_request_in_local_satp_db, - log_request_state_in_local_satp_db, spawn_send_transfer_commence_request, + create_transfer_proposal_claims_request, get_relay_from_transfer_proposal_claims, + get_relay_params, get_request_id_from_transfer_proposal_claims, log_request_in_local_satp_db, + log_request_state_in_local_satp_db, spawn_send_transfer_proposal_claims_request, }; // External modules @@ -526,9 +527,10 @@ impl Network for NetworkService { ); let conf = self.config_lock.read().await.clone(); let network_asset_transfer = request.into_inner().clone(); - let transfer_commence_request: TransferCommenceRequest = - derive_transfer_commence_request(network_asset_transfer.clone()); - let request_id = transfer_commence_request.session_id.to_string(); + let transfer_proposal_claims_request: TransferProposalClaimsRequest = + create_transfer_proposal_claims_request(network_asset_transfer.clone()); + let request_id = + get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); // TODO refactor let request_logged: Result, crate::error::Error> = log_request_in_local_satp_db(&request_id, &network_asset_transfer, conf.clone()); @@ -588,13 +590,21 @@ impl Network for NetworkService { let parsed_address = parse_address(network_asset_transfer.address.to_string()); match parsed_address { Ok(address) => { + let (relay_host, relay_port) = get_relay_from_transfer_proposal_claims( + transfer_proposal_claims_request.clone(), + ); + let (use_tls, relay_tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + // TODO: verify that host and port are valid // Spawns a child process to handle sending request - spawn_send_transfer_commence_request( + spawn_send_transfer_proposal_claims_request( + transfer_proposal_claims_request, + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path, conf, - transfer_commence_request, - address.location.hostname.to_string(), - address.location.port.to_string(), ); // Send Ack back to network while request is happening in a thread let reply = Ack { diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 400d2e6b49..9405543f35 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -1,6 +1,6 @@ use config::Config; use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use sled::IVec; use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use tonic::Response; @@ -8,64 +8,139 @@ use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::state::{request_state, RequestState}; use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; -use weaverpb::relay::satp::{AckCommenceRequest, TransferCommenceRequest, LockAssertionRequest}; +use weaverpb::relay::satp::{ + AckCommenceRequest, LockAssertionRequest, TransferCommenceRequest, + TransferProposalClaimsRequest, TransferProposalReceiptRequest, +}; use crate::db::Database; use crate::error::{self, Error}; use crate::relay_proto::LocationSegment; -use super::constants::{SATP_DB_PATH, SATP_REQUESTS_DB_PATH, SATP_REMOTE_REQUESTS_DB_PATH, SATP_REMOTE_REQUESTS_STATES_DB_PATH, SATP_REQUESTS_STATES_DB_PATH}; +use super::constants::{ + SATP_DB_PATH, SATP_REMOTE_REQUESTS_DB_PATH, SATP_REMOTE_REQUESTS_STATES_DB_PATH, + SATP_REQUESTS_DB_PATH, SATP_REQUESTS_STATES_DB_PATH, +}; + +// Sends a request to the receiving gateway +pub fn spawn_send_transfer_proposal_claims_request( + transfer_proposal_claims_request: TransferProposalClaimsRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + relay_tlsca_cert_path: String, + conf: Config, +) { + println!( + "Sending transfer proposal claims request to receiver gateway: {:?}:{:?}", + relay_host, relay_port + ); + // Spawning new thread to make the call_transfer_proposal_claims to receiver gateway + tokio::spawn(async move { + let request_id = + get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); + println!( + "Sending transfer proposal claims request to receiver gateway: Request ID = {:?}", + request_id + ); + let result = call_transfer_proposal_claims( + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path.to_string(), + transfer_proposal_claims_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} // Sends a request to the receiving gateway pub fn spawn_send_transfer_commence_request( - conf: config::Config, transfer_commence_request: TransferCommenceRequest, - receiver_relay_host: String, - receiver_relay_port: String, + relay_host: String, + relay_port: String, + use_tls: bool, + relay_tlsca_cert_path: String, + conf: Config, ) { println!( "Sending transfer commence request to receiver gateway: {:?}:{:?}", - receiver_relay_host, receiver_relay_port + relay_host, relay_port ); - // Spawning new thread to make the call_asset_transfer to receiver gateway + // Spawning new thread to make the call_transfer_commence to receiver gateway tokio::spawn(async move { - let (use_tls, relay_tlsca_cert_path) = get_relay_params( - receiver_relay_host.clone(), - receiver_relay_port.clone(), - conf.clone(), - ); let request_id = transfer_commence_request.session_id.to_string(); + println!( + "Sending transfer commence request to receiver gateway: Request ID = {:?}", + request_id + ); let result = call_transfer_commence( - receiver_relay_host, - receiver_relay_port, + relay_host, + relay_port, use_tls, relay_tlsca_cert_path.to_string(), transfer_commence_request.clone(), ) .await; - println!("Received Ack from receiver gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the receiving gateway + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_transfer_proposal_receipt_request( + transfer_proposal_receipt_request: TransferProposalReceiptRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + relay_tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = get_request_id_from_transfer_proposal_receipt( + transfer_proposal_receipt_request.clone(), + ); + println!( + "Sending transfer proposal receipt back to sending gateway: Request ID = {:?}", + request_id + ); + let result = call_transfer_proposal_receipt( + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path.to_string(), + transfer_proposal_receipt_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway log_request_result_in_local_satp_db(&request_id, result, conf); }); } pub fn spawn_send_ack_commence_request( ack_commence_request: AckCommenceRequest, - requesting_relay_host: String, - requesting_relay_port: String, + relay_host: String, + relay_port: String, use_tls: bool, relay_tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { + let request_id = ack_commence_request.session_id.to_string(); println!( "Sending commence response back to sending gateway: Request ID = {:?}", - ack_commence_request.session_id + request_id ); let result = call_ack_commence( - requesting_relay_host, - requesting_relay_port, + relay_host, + relay_port, use_tls, relay_tlsca_cert_path.to_string(), ack_commence_request.clone(), @@ -74,15 +149,14 @@ pub fn spawn_send_ack_commence_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - let request_id = ack_commence_request.session_id.to_string(); log_request_result_in_local_satp_db(&request_id, result, conf); }); } pub fn spawn_send_perform_lock_request( lock_assertion_request: LockAssertionRequest, - requesting_relay_host: String, - requesting_relay_port: String, + relay_host: String, + relay_port: String, use_tls: bool, relay_tlsca_cert_path: String, conf: Config, @@ -98,8 +172,8 @@ pub fn spawn_send_perform_lock_request( // Once the asset is locked, call the lock_assertion endpoint // log the results let result = call_lock_assertion( - requesting_relay_host, - requesting_relay_port, + relay_host, + relay_port, use_tls, relay_tlsca_cert_path.to_string(), lock_assertion_request.clone(), @@ -133,6 +207,46 @@ pub async fn call_transfer_commence( Ok(response) } +// Call the call_transfer_proposal_claims endpoint on the receiver gateway +pub async fn call_transfer_proposal_claims( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + transfer_proposal_claims_request: TransferProposalClaimsRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the transfer proposal claims request: {:?}", + transfer_proposal_claims_request.clone() + ); + let response = satp_client + .transfer_proposal_claims(transfer_proposal_claims_request.clone()) + .await?; + Ok(response) +} + +// Call the call_transfer_proposal_receipt endpoint on the sending gateway +pub async fn call_transfer_proposal_receipt( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + transfer_proposal_receipt_request: TransferProposalReceiptRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the transfer proposal receipt request: {:?}", + transfer_proposal_receipt_request.clone() + ); + let response = satp_client + .transfer_proposal_receipt(transfer_proposal_receipt_request.clone()) + .await?; + Ok(response) +} + // Call the ack_commence endpoint on the sending gateway pub async fn call_ack_commence( relay_host: String, @@ -233,8 +347,30 @@ pub fn create_ack_error_message( return reply; } -pub fn derive_transfer_commence_request( +pub fn create_transfer_proposal_claims_request( network_asset_transfer: NetworkAssetTransfer, +) -> TransferProposalClaimsRequest { + let session_id = "to_be_calculated_session_id"; + let transfer_proposal_claims_request = TransferProposalClaimsRequest { + message_type: "message_type1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + asset_asset_id: "asset_asset_id".to_string(), + asset_profile_id: "asset_profile_id".to_string(), + verified_originator_entity_id: "verified_originator_entity_id".to_string(), + verified_beneficiary_entity_id: "verified_beneficiary_entity_id".to_string(), + originator_pubkey: "originator_pubkey".to_string(), + beneficiary_pubkey: "beneficiary_pubkey".to_string(), + sender_gateway_network_id: "sender_gateway_network_id".to_string(), + recipient_gateway_network_id: "recipient_gateway_network_id".to_string(), + sender_gateway_owner_id: "sender_gateway_owner_id".to_string(), + receiver_gateway_owner_id: "receiver_gateway_owner_id".to_string(), + }; + return transfer_proposal_claims_request; +} + +pub fn create_transfer_commence_request( + transfer_proposal_receipt_request: TransferProposalReceiptRequest, ) -> TransferCommenceRequest { let session_id = "to_be_calculated_session_id"; let transfer_commence_request = TransferCommenceRequest { @@ -248,13 +384,35 @@ pub fn derive_transfer_commence_request( client_transfer_number: "client_transfer_number1".to_string(), client_signature: "client_signature1".to_string(), }; - return transfer_commence_request; } +pub fn create_transfer_proposal_receipt_request( + transfer_proposal_claims_request: TransferProposalClaimsRequest, +) -> TransferProposalReceiptRequest { + // TODO: remove hard coded values + let transfer_proposal_receipt_request = TransferProposalReceiptRequest { + message_type: "message_type1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + asset_asset_id: "asset_asset_id".to_string(), + asset_profile_id: "asset_profile_id".to_string(), + verified_originator_entity_id: "verified_originator_entity_id".to_string(), + verified_beneficiary_entity_id: "verified_beneficiary_entity_id".to_string(), + originator_pubkey: "originator_pubkey".to_string(), + beneficiary_pubkey: "beneficiary_pubkey".to_string(), + sender_gateway_network_id: "sender_gateway_network_id".to_string(), + recipient_gateway_network_id: "recipient_gateway_network_id".to_string(), + sender_gateway_owner_id: "sender_gateway_owner_id".to_string(), + receiver_gateway_owner_id: "receiver_gateway_owner_id".to_string(), + }; + return transfer_proposal_receipt_request; +} + pub fn create_ack_commence_request( transfer_commence_request: TransferCommenceRequest, ) -> AckCommenceRequest { + // TODO: remove hard coded values let ack_commence_request = AckCommenceRequest { message_type: "message_type1".to_string(), session_id: "session_id1".to_string(), @@ -271,6 +429,7 @@ pub fn create_ack_commence_request( pub fn create_lock_assertion_request( ack_commence_request: AckCommenceRequest, ) -> LockAssertionRequest { + // TODO: remove hard coded values let lock_assertion_request = LockAssertionRequest { message_type: "message_type1".to_string(), session_id: "session_id1".to_string(), @@ -289,7 +448,11 @@ pub fn create_lock_assertion_request( pub fn get_satp_requests_local_db(conf: Config) -> Database { let db = Database { - db_path: format!("{}{}", conf.get_str(SATP_DB_PATH).unwrap(), SATP_REQUESTS_DB_PATH), + db_path: format!( + "{}{}", + conf.get_str(SATP_DB_PATH).unwrap(), + SATP_REQUESTS_DB_PATH + ), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, }; @@ -298,7 +461,11 @@ pub fn get_satp_requests_local_db(conf: Config) -> Database { pub fn get_satp_requests_remote_db(conf: Config) -> Database { let db = Database { - db_path: format!("{}{}", conf.get_str(SATP_DB_PATH).unwrap(), SATP_REMOTE_REQUESTS_DB_PATH), + db_path: format!( + "{}{}", + conf.get_str(SATP_DB_PATH).unwrap(), + SATP_REMOTE_REQUESTS_DB_PATH + ), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, }; @@ -307,7 +474,11 @@ pub fn get_satp_requests_remote_db(conf: Config) -> Database { pub fn get_satp_requests_states_local_db(conf: Config) -> Database { let db = Database { - db_path: format!("{}{}", conf.get_str(SATP_DB_PATH).unwrap(), SATP_REQUESTS_STATES_DB_PATH), + db_path: format!( + "{}{}", + conf.get_str(SATP_DB_PATH).unwrap(), + SATP_REQUESTS_STATES_DB_PATH + ), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, }; @@ -316,7 +487,11 @@ pub fn get_satp_requests_states_local_db(conf: Config) -> Database { pub fn get_satp_requests_states_remote_db(conf: Config) -> Database { let db = Database { - db_path: format!("{}{}", conf.get_str(SATP_DB_PATH).unwrap(), SATP_REMOTE_REQUESTS_STATES_DB_PATH), + db_path: format!( + "{}{}", + conf.get_str(SATP_DB_PATH).unwrap(), + SATP_REMOTE_REQUESTS_STATES_DB_PATH + ), db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, }; @@ -379,6 +554,22 @@ pub fn update_request_state_in_local_satp_db( println!("{:?}\n", db.get::(request_id).unwrap()) } +// Get the requesting relay host and port +pub fn get_relay_from_transfer_proposal_claims( + transfer_proposal_claims_request: TransferProposalClaimsRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +// Get the requesting relay host and port +pub fn get_relay_from_transfer_proposal_receipt( + transfer_proposal_receipt_request: TransferProposalReceiptRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + // Get the requesting relay host and port pub fn get_relay_from_transfer_commence( transfer_commence_request: TransferCommenceRequest, @@ -388,9 +579,7 @@ pub fn get_relay_from_transfer_commence( } // Get the requesting relay host and port -pub fn get_relay_from_ack_commence( - ack_commence_request: AckCommenceRequest, -) -> (String, String) { +pub fn get_relay_from_ack_commence(ack_commence_request: AckCommenceRequest) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } @@ -440,3 +629,17 @@ pub async fn create_satp_client( } return Ok(satp_client); } + +pub fn get_request_id_from_transfer_proposal_claims( + request: TransferProposalClaimsRequest, +) -> String { + // TODO + return "hard_coded_transfer_proposal_claims_request_id".to_string(); +} + +pub fn get_request_id_from_transfer_proposal_receipt( + request: TransferProposalReceiptRequest, +) -> String { + // TODO + return "hard_coded_transfer_proposal_receipt_request_id".to_string(); +} diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 618d1aac01..8037f6127e 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -3,19 +3,25 @@ use weaverpb::common::ack::{ack, Ack}; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{ AckCommenceRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, + TransferProposalClaimsRequest, TransferProposalReceiptRequest, }; // Internal modules use crate::error::Error; use crate::services::satp_helper::{ - create_ack_error_message, log_request_in_local_satp_db, log_request_in_remote_satp_db, + create_ack_error_message, get_request_id_from_transfer_proposal_receipt, + log_request_in_local_satp_db, log_request_in_remote_satp_db, }; // external modules use super::satp_helper::{ - create_ack_commence_request, create_lock_assertion_request, get_relay_from_ack_commence, - get_relay_from_transfer_commence, get_relay_params, spawn_send_ack_commence_request, - spawn_send_perform_lock_request, + create_ack_commence_request, create_lock_assertion_request, create_transfer_commence_request, + create_transfer_proposal_receipt_request, get_relay_from_ack_commence, + get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, + get_relay_from_transfer_proposal_receipt, get_relay_params, + get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, + spawn_send_perform_lock_request, spawn_send_transfer_commence_request, + spawn_send_transfer_proposal_receipt_request, }; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; @@ -29,6 +35,119 @@ pub struct SatpService { /// communication of the asset transfer protocol SATP between two gateways. #[tonic::async_trait] impl Satp for SatpService { + /// transfer_proposal_claims is run on the receiver gateway to allow the sender gateway to initiate an asset transfer. + async fn transfer_proposal_claims( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got a TransferProposalClaimsRequest from {:?} - {:?}", + request.remote_addr(), + request + ); + + let transfer_proposal_claims_request = request.into_inner().clone(); + let request_id = + get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); + let conf = self.config_lock.read().await; + + match log_request_in_remote_satp_db( + &request_id, + &transfer_proposal_claims_request, + conf.clone(), + ) { + Ok(_) => { + println!("Successfully stored TransferProposalClaimsRequest in remote satp_db with request_id: {}", request_id); + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing TransferProposalClaimsRequest in remote satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_transfer_proposal_claims_request( + transfer_proposal_claims_request, + conf.clone(), + ) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of transfer proposal claims request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Transfer proposal claims failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn transfer_proposal_receipt( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got an ack transfer proposal receipt request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let transfer_proposal_receipt_request = request.into_inner().clone(); + let request_id = get_request_id_from_transfer_proposal_receipt( + transfer_proposal_receipt_request.clone(), + ); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = log_request_in_local_satp_db( + &request_id, + &transfer_proposal_receipt_request, + conf.clone(), + ); + match request_logged { + Ok(_) => { + println!( + "Successfully stored TransferProposalReceiptRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing TransferProposalReceiptRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_transfer_proposal_receipt_request( + transfer_proposal_receipt_request, + conf.clone(), + ) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of transfer proposal receipt request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Ack transfer proposal receipt failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + /// transfer_commence is run on the receiver gateway to allow the sender gateway to signal to the /// receiver gateway that it is ready to start the transfer of the digital asset async fn transfer_commence( @@ -160,6 +279,78 @@ impl Satp for SatpService { } } +pub fn process_transfer_proposal_claims_request( + transfer_proposal_claims_request: TransferProposalClaimsRequest, + conf: config::Config, +) -> Result { + let request_id = + get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); + let is_valid_request = + is_valid_transfer_proposal_claims_request(transfer_proposal_claims_request.clone()); + + if is_valid_request { + println!("The transfer proposal claims request is valid\n"); + match send_transfer_proposal_receipt_request(transfer_proposal_claims_request, conf) { + Ok(ack) => { + println!("Ack transfer proposal claims request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: Ack transfer proposal claims failed. {:?}", e), + }); + } + } + } else { + println!("The transfer proposal claims request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The transfer proposal claims request is invalid".to_string(), + }); + } +} + +pub fn process_transfer_proposal_receipt_request( + transfer_proposal_receipt_request: TransferProposalReceiptRequest, + conf: config::Config, +) -> Result { + let request_id = + get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); + let is_valid_request = + is_valid_transfer_proposal_receipt_request(transfer_proposal_receipt_request.clone()); + + if is_valid_request { + println!("The transfer proposal receipt request is valid\n"); + match send_transfer_commence_request(transfer_proposal_receipt_request, conf) { + Ok(ack) => { + println!("Ack transfer proposal receipt request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: Ack transfer proposal receipt failed. {:?}", e), + }); + } + } + } else { + println!("The transfer proposal receipt request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The transfer proposal receipt request is invalid".to_string(), + }); + } +} + /// process_transfer_commence_request is run on the receiver gateway to initiate asset transfer protocol that was /// requested from the sender gateway pub fn process_transfer_commence_request( @@ -196,6 +387,43 @@ pub fn process_transfer_commence_request( } } +pub fn process_tranfer_proposal_receipt_request( + transfer_proposal_receipt_request: TransferProposalReceiptRequest, + conf: config::Config, +) -> Result { + let request_id = + get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); + let is_valid_request = + is_valid_transfer_proposal_receipt_request(transfer_proposal_receipt_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The transfer proposal receipt request is valid\n"); + match send_transfer_commence_request(transfer_proposal_receipt_request, conf) { + Ok(ack) => { + println!("Ack transfer proposal receipt request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: Ack transfer proposal receipt failed. {:?}", e), + }); + } + } + } else { + println!("The transfer proposal receipt request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The transfer proposal receipt request is invalid".to_string(), + }); + } +} + /// process_ack_commence_request is invoked by the receiver gateway to ack the transfer commence request /// requested ed by the sender gateway pub fn process_ack_commence_request( @@ -233,24 +461,79 @@ pub fn process_ack_commence_request( } } +fn send_transfer_proposal_receipt_request( + transfer_proposal_claims_request: TransferProposalClaimsRequest, + conf: config::Config, +) -> Result { + let request_id = + get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); + let (relay_host, relay_port) = + get_relay_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); + let (use_tls, relay_tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let transfer_proposal_receipt_request = + create_transfer_proposal_receipt_request(transfer_proposal_claims_request.clone()); + + spawn_send_transfer_proposal_receipt_request( + transfer_proposal_receipt_request, + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Transfer Proposal Claims request".to_string(), + }; + return Ok(reply); +} + +fn send_transfer_commence_request( + transfer_proposal_receipt_request: TransferProposalReceiptRequest, + conf: config::Config, +) -> Result { + let request_id = + get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); + let (relay_host, relay_port) = + get_relay_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); + let (use_tls, relay_tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let transfer_commence_request = + create_transfer_commence_request(transfer_proposal_receipt_request.clone()); + + spawn_send_transfer_commence_request( + transfer_commence_request, + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Transfer Proposal Claims request".to_string(), + }; + return Ok(reply); +} + fn send_ack_commence_request( transfer_commence_request: TransferCommenceRequest, conf: config::Config, ) -> Result { let request_id = &transfer_commence_request.session_id.to_string(); - let (requesting_relay_host, requesting_relay_port) = + let (relay_host, relay_port) = get_relay_from_transfer_commence(transfer_commence_request.clone()); - let (use_tls, relay_tlsca_cert_path) = get_relay_params( - requesting_relay_host.clone(), - requesting_relay_port.clone(), - conf.clone(), - ); + let (use_tls, relay_tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let ack_commence_request = create_ack_commence_request(transfer_commence_request.clone()); spawn_send_ack_commence_request( ack_commence_request, - requesting_relay_host, - requesting_relay_port, + relay_host, + relay_port, use_tls, relay_tlsca_cert_path, conf, @@ -268,19 +551,15 @@ fn send_perform_lock_request( conf: config::Config, ) -> Result { let request_id = &ack_commence_request.session_id.to_string(); - let (requesting_relay_host, requesting_relay_port) = - get_relay_from_ack_commence(ack_commence_request.clone()); - let (use_tls, relay_tlsca_cert_path) = get_relay_params( - requesting_relay_host.clone(), - requesting_relay_port.clone(), - conf.clone(), - ); + let (relay_host, relay_port) = get_relay_from_ack_commence(ack_commence_request.clone()); + let (use_tls, relay_tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let perfrom_lock_request = create_lock_assertion_request(ack_commence_request.clone()); spawn_send_perform_lock_request( perfrom_lock_request, - requesting_relay_host, - requesting_relay_port, + relay_host, + relay_port, use_tls, relay_tlsca_cert_path, conf, @@ -293,6 +572,20 @@ fn send_perform_lock_request( return Ok(reply); } +fn is_valid_transfer_proposal_claims_request( + transfer_proposal_claims_request: TransferProposalClaimsRequest, +) -> bool { + //TODO + true +} + +fn is_valid_transfer_proposal_receipt_request( + transfer_proposal_receipt_request: TransferProposalReceiptRequest, +) -> bool { + //TODO + true +} + fn is_valid_transfer_commence_request(transfer_commence_request: TransferCommenceRequest) -> bool { //TODO true From 3819abc992f4a69473e68cd5e26ee8d110847c32 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Wed, 2 Aug 2023 10:04:33 +0100 Subject: [PATCH 14/59] implemented the lock assertion method --- weaver/core/relay/src/services/satp_helper.rs | 86 +++++++++++++- .../core/relay/src/services/satp_service.rs | 111 ++++++++++++++++-- 2 files changed, 183 insertions(+), 14 deletions(-) diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 9405543f35..95e352fe45 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -10,7 +10,7 @@ use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ AckCommenceRequest, LockAssertionRequest, TransferCommenceRequest, - TransferProposalClaimsRequest, TransferProposalReceiptRequest, + TransferProposalClaimsRequest, TransferProposalReceiptRequest, LockAssertionReceiptRequest, }; use crate::db::Database; @@ -187,6 +187,35 @@ pub fn spawn_send_perform_lock_request( }); } +pub fn spawn_send_lock_assertion_receipt_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + relay_tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = lock_assertion_receipt_request.session_id.to_string(); + println!( + "Sending lock assertion receipt back to sending gateway: Request ID = {:?}", + request_id + ); + let result = call_lock_assertion_receipt( + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path.to_string(), + lock_assertion_receipt_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + // Call the transfer_commence endpoint on the receiver gateway pub async fn call_transfer_commence( relay_host: String, @@ -287,6 +316,26 @@ pub async fn call_lock_assertion( Ok(response) } +// Call the ack_commence endpoint on the sending gateway +pub async fn call_lock_assertion_receipt( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the lock assertion receipt request: {:?}", + lock_assertion_receipt_request.clone() + ); + let response = satp_client + .lock_assertion_receipt(lock_assertion_receipt_request.clone()) + .await?; + Ok(response) +} + pub fn log_request_result_in_local_satp_db( request_id: &String, result: Result, Box>, @@ -446,6 +495,23 @@ pub fn create_lock_assertion_request( return lock_assertion_request; } +pub fn create_lock_assertion_receipt_request( + lock_assertion_request: LockAssertionRequest, +) -> LockAssertionReceiptRequest { + // TODO: remove hard coded values + let lock_assertion_receipt_request = LockAssertionReceiptRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + hash_prev_message: "hash_prev_message1".to_string(), + server_transfer_number: "server_transfer_number1".to_string(), + server_signature: "server_signature1".to_string(), + }; + return lock_assertion_receipt_request; +} + pub fn get_satp_requests_local_db(conf: Config) -> Database { let db = Database { db_path: format!( @@ -554,7 +620,6 @@ pub fn update_request_state_in_local_satp_db( println!("{:?}\n", db.get::(request_id).unwrap()) } -// Get the requesting relay host and port pub fn get_relay_from_transfer_proposal_claims( transfer_proposal_claims_request: TransferProposalClaimsRequest, ) -> (String, String) { @@ -562,7 +627,6 @@ pub fn get_relay_from_transfer_proposal_claims( return ("localhost".to_string(), "9085".to_string()); } -// Get the requesting relay host and port pub fn get_relay_from_transfer_proposal_receipt( transfer_proposal_receipt_request: TransferProposalReceiptRequest, ) -> (String, String) { @@ -570,7 +634,6 @@ pub fn get_relay_from_transfer_proposal_receipt( return ("localhost".to_string(), "9085".to_string()); } -// Get the requesting relay host and port pub fn get_relay_from_transfer_commence( transfer_commence_request: TransferCommenceRequest, ) -> (String, String) { @@ -578,12 +641,25 @@ pub fn get_relay_from_transfer_commence( return ("localhost".to_string(), "9085".to_string()); } -// Get the requesting relay host and port pub fn get_relay_from_ack_commence(ack_commence_request: AckCommenceRequest) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } +pub fn get_relay_from_lock_assertion( + lock_assertion_request: LockAssertionRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_lock_assertion_receipt( + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 8037f6127e..35e778b0d8 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -21,7 +21,7 @@ use super::satp_helper::{ get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, spawn_send_perform_lock_request, spawn_send_transfer_commence_request, - spawn_send_transfer_proposal_receipt_request, + spawn_send_transfer_proposal_receipt_request, get_relay_from_lock_assertion, create_lock_assertion_receipt_request, get_relay_from_lock_assertion_receipt, spawn_send_lock_assertion_receipt_request, }; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; @@ -247,17 +247,44 @@ impl Satp for SatpService { request: Request, ) -> Result, Status> { println!( - "Got a lock assertion request from {:?} - {:?}", + "Got a LockAssertionRequest from {:?} - {:?}", request.remote_addr(), request ); - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: "xxxxxxxxx".to_string(), - message: format!("Error: Not implemented yet."), - })); - println!("Sending back Ack: {:?}\n", reply); - reply + + let lock_assertion_request = request.into_inner().clone(); + let request_id = lock_assertion_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + match log_request_in_remote_satp_db(&request_id, &lock_assertion_request, conf.clone()) { + Ok(_) => { + println!("Successfully stored LockAssertionRequest in remote satp_db with request_id: {}", request_id); + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing LockAssertionRequest in remote satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_lock_assertion_request(lock_assertion_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of lock assertion request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Lock assertion failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } } async fn lock_assertion_receipt( @@ -461,6 +488,40 @@ pub fn process_ack_commence_request( } } +pub fn process_lock_assertion_request( + lock_assertion_request: LockAssertionRequest, + conf: config::Config, +) -> Result { + let request_id = lock_assertion_request.session_id.to_string(); + let is_valid_request = is_valid_lock_assertion_request(lock_assertion_request.clone()); + + if is_valid_request { + println!("The lock assertion request is valid\n"); + match send_lock_assertion_receipt_request(lock_assertion_request, conf) { + Ok(ack) => { + println!("Ack lock assertion request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: Ack lock assertion failed. {:?}", e), + }); + } + } + } else { + println!("The lock assertion request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The lock assertion request is invalid".to_string(), + }); + } +} + fn send_transfer_proposal_receipt_request( transfer_proposal_claims_request: TransferProposalClaimsRequest, conf: config::Config, @@ -546,6 +607,33 @@ fn send_ack_commence_request( return Ok(reply); } +fn send_lock_assertion_receipt_request( + lock_assertion_request: LockAssertionRequest, + conf: config::Config, +) -> Result { + let request_id = &lock_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_lock_assertion(lock_assertion_request.clone()); + let (use_tls, relay_tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let lock_assertion_receipt_request = create_lock_assertion_receipt_request(lock_assertion_request.clone()); + + spawn_send_lock_assertion_receipt_request( + lock_assertion_receipt_request, + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Lock Assertion request".to_string(), + }; + return Ok(reply); +} + fn send_perform_lock_request( ack_commence_request: AckCommenceRequest, conf: config::Config, @@ -595,3 +683,8 @@ fn is_valid_ack_commence_request(ack_commence_request: AckCommenceRequest) -> bo //TODO true } + +fn is_valid_lock_assertion_request(lock_assertion_request: LockAssertionRequest) -> bool { + //TODO + true +} \ No newline at end of file From 4aeea5b34e276a461a7eb8715e536eb78ccaffb7 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Wed, 2 Aug 2023 11:50:38 +0100 Subject: [PATCH 15/59] Added the lock-assertion-receipt and lock-assertion-broadcast methods --- weaver/core/relay/src/services/satp_helper.rs | 22 ++- .../core/relay/src/services/satp_service.rs | 164 +++++++++++++++--- 2 files changed, 155 insertions(+), 31 deletions(-) diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 95e352fe45..88f97cacf9 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -9,8 +9,8 @@ use weaverpb::common::state::{request_state, RequestState}; use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ - AckCommenceRequest, LockAssertionRequest, TransferCommenceRequest, - TransferProposalClaimsRequest, TransferProposalReceiptRequest, LockAssertionReceiptRequest, + AckCommenceRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, + TransferProposalClaimsRequest, TransferProposalReceiptRequest, }; use crate::db::Database; @@ -162,9 +162,10 @@ pub fn spawn_send_perform_lock_request( conf: Config, ) { tokio::spawn(async move { + let request_id = lock_assertion_request.session_id.to_string(); println!( - "Locking the asset of the lock assertion request {:?}", - lock_assertion_request + "Locking the asset of the lock assertion request id: {:?}", + request_id ); // TODO // Call the driver to check the asset status @@ -187,7 +188,7 @@ pub fn spawn_send_perform_lock_request( }); } -pub fn spawn_send_lock_assertion_receipt_request( +pub fn spawn_send_lock_assertion_broadcast_request( lock_assertion_receipt_request: LockAssertionReceiptRequest, relay_host: String, relay_port: String, @@ -197,10 +198,12 @@ pub fn spawn_send_lock_assertion_receipt_request( ) { tokio::spawn(async move { let request_id = lock_assertion_receipt_request.session_id.to_string(); - println!( - "Sending lock assertion receipt back to sending gateway: Request ID = {:?}", - request_id - ); + println!("Broadcasting the lock assertion request {:?}", request_id); + // TODO + // Broadcast the message to the network + // Subscribe to the status event + // Once the message is broadcast, call the call_lock_assertion_receipt endpoint + // log the results let result = call_lock_assertion_receipt( relay_host, relay_port, @@ -212,6 +215,7 @@ pub fn spawn_send_lock_assertion_receipt_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway + let request_id = lock_assertion_receipt_request.session_id.to_string(); log_request_result_in_local_satp_db(&request_id, result, conf); }); } diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 35e778b0d8..71fe74b7d0 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -15,13 +15,15 @@ use crate::services::satp_helper::{ // external modules use super::satp_helper::{ - create_ack_commence_request, create_lock_assertion_request, create_transfer_commence_request, + create_ack_commence_request, create_lock_assertion_receipt_request, + create_lock_assertion_request, create_transfer_commence_request, create_transfer_proposal_receipt_request, get_relay_from_ack_commence, - get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, - get_relay_from_transfer_proposal_receipt, get_relay_params, - get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, + get_relay_from_lock_assertion, get_relay_from_transfer_commence, + get_relay_from_transfer_proposal_claims, get_relay_from_transfer_proposal_receipt, + get_relay_params, get_request_id_from_transfer_proposal_claims, + spawn_send_ack_commence_request, spawn_send_lock_assertion_broadcast_request, spawn_send_perform_lock_request, spawn_send_transfer_commence_request, - spawn_send_transfer_proposal_receipt_request, get_relay_from_lock_assertion, create_lock_assertion_receipt_request, get_relay_from_lock_assertion_receipt, spawn_send_lock_assertion_receipt_request, + spawn_send_transfer_proposal_receipt_request, }; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; @@ -273,10 +275,7 @@ impl Satp for SatpService { match process_lock_assertion_request(lock_assertion_request, conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); - println!( - "Sending Ack of lock assertion request back: {:?}\n", - reply - ); + println!("Sending Ack of lock assertion request back: {:?}\n", reply); reply } Err(e) => { @@ -292,17 +291,53 @@ impl Satp for SatpService { request: Request, ) -> Result, Status> { println!( - "Got a lock assertion receipt request from {:?} - {:?}", + "Got an lock assertion receipt request from {:?} - {:?}", request.remote_addr(), request ); - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: "xxxxxxxxx".to_string(), - message: format!("Error: Not implemented yet."), - })); - println!("Sending back Ack: {:?}\n", reply); - reply + + let lock_assertion_receipt_request = request.into_inner().clone(); + let request_id = lock_assertion_receipt_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = log_request_in_local_satp_db( + &request_id, + &lock_assertion_receipt_request, + conf.clone(), + ); + match request_logged { + Ok(_) => { + println!( + "Successfully stored LockAssertionReceiptRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing LockAssertionReceiptRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_lock_assertion_receipt_request(lock_assertion_receipt_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of lock assertion receipt request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Lock assertion receipt failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } } } @@ -522,6 +557,42 @@ pub fn process_lock_assertion_request( } } +pub fn process_lock_assertion_receipt_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, + conf: config::Config, +) -> Result { + let request_id = lock_assertion_receipt_request.session_id.to_string(); + let is_valid_request = + is_valid_lock_assertion_receipt_request(lock_assertion_receipt_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The lock assertion receipt request is valid\n"); + match send_commit_prepare_request(lock_assertion_receipt_request, conf) { + Ok(ack) => { + println!("Ack lock assertion receipt request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: perform lock request failed. {:?}", e), + }); + } + } + } else { + println!("The lock assertion receipt request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The lock assertion receipt request is invalid".to_string(), + }); + } +} + fn send_transfer_proposal_receipt_request( transfer_proposal_claims_request: TransferProposalClaimsRequest, conf: config::Config, @@ -612,13 +683,13 @@ fn send_lock_assertion_receipt_request( conf: config::Config, ) -> Result { let request_id = &lock_assertion_request.session_id.to_string(); - let (relay_host, relay_port) = - get_relay_from_lock_assertion(lock_assertion_request.clone()); + let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); let (use_tls, relay_tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let lock_assertion_receipt_request = create_lock_assertion_receipt_request(lock_assertion_request.clone()); + let lock_assertion_receipt_request = + create_lock_assertion_receipt_request(lock_assertion_request.clone()); - spawn_send_lock_assertion_receipt_request( + spawn_send_lock_assertion_broadcast_request( lock_assertion_receipt_request, relay_host, relay_port, @@ -652,6 +723,7 @@ fn send_perform_lock_request( relay_tlsca_cert_path, conf, ); + let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), @@ -660,6 +732,47 @@ fn send_perform_lock_request( return Ok(reply); } +fn send_lock_assertion_broadcast_request( + lock_assertion_request: LockAssertionRequest, + conf: config::Config, +) -> Result { + let request_id = &lock_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); + let (use_tls, relay_tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let lock_assertion_receipt_request = + create_lock_assertion_receipt_request(lock_assertion_request.clone()); + + spawn_send_lock_assertion_broadcast_request( + lock_assertion_receipt_request, + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of lock assert request".to_string(), + }; + return Ok(reply); +} + +fn send_commit_prepare_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &lock_assertion_receipt_request.session_id.to_string(); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Lock Assertion Receipt request".to_string(), + }; + return Ok(reply); +} + fn is_valid_transfer_proposal_claims_request( transfer_proposal_claims_request: TransferProposalClaimsRequest, ) -> bool { @@ -687,4 +800,11 @@ fn is_valid_ack_commence_request(ack_commence_request: AckCommenceRequest) -> bo fn is_valid_lock_assertion_request(lock_assertion_request: LockAssertionRequest) -> bool { //TODO true -} \ No newline at end of file +} + +fn is_valid_lock_assertion_receipt_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> bool { + //TODO + true +} From 5fee4cb258d77f1f3fa69c3fac79ff7b57f1b076 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Thu, 3 Aug 2023 11:47:25 +0100 Subject: [PATCH 16/59] Added the request to the driver to lock an asset --- .../pkg/src/generated/driver.driver.rs | 77 +++++++++++++++++++ .../protos-rs/pkg/src/generated/relay.satp.rs | 8 +- weaver/common/protos/driver/driver.proto | 6 ++ weaver/core/relay/driver/driver.rs | 14 +++- weaver/core/relay/src/services/satp_helper.rs | 58 +++++++++++++- .../core/relay/src/services/satp_service.rs | 57 +++++++++----- 6 files changed, 192 insertions(+), 28 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs index 99586a72d4..011b4085a0 100644 --- a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs +++ b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs @@ -8,6 +8,10 @@ pub struct WriteExternalStateMessage { #[prost(message, optional, tag = "2")] pub ctx: ::core::option::Option, } +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerformLockRequest {} /// Generated client implementations. pub mod driver_communication_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] @@ -179,6 +183,30 @@ pub mod driver_communication_client { ); self.inner.unary(request.into_request(), path, codec).await } + /// As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + /// to lock a specific asset + pub async fn perform_lock( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/PerformLock", + ); + self.inner.unary(request.into_request(), path, codec).await + } } } /// Generated server implementations. @@ -230,6 +258,15 @@ pub mod driver_communication_server { tonic::Response, tonic::Status, >; + /// As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + /// to lock a specific asset + async fn perform_lock( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct DriverCommunicationServer { @@ -465,6 +502,46 @@ pub mod driver_communication_server { }; Box::pin(fut) } + "/driver.driver.DriverCommunication/PerformLock" => { + #[allow(non_camel_case_types)] + struct PerformLockSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for PerformLockSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).perform_lock(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = PerformLockSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index 0031a5dacd..743a57a40b 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -221,7 +221,7 @@ pub mod satp_client { self.inner = self.inner.accept_compressed(encoding); self } - /// The sender gateway sends a TransferProposalClaims request to to initiate an asset transfer. + /// The sender gateway sends a TransferProposalClaims request to initiate an asset transfer. /// Depending on the proposal, multiple rounds of communication between the two gateways may happen. pub async fn transfer_proposal_claims( &mut self, @@ -319,7 +319,7 @@ pub mod satp_client { } /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway /// declaring that the asset in question has been locked or escrowed by the sender gateway in - /// the origin network (e.g. to prevent double spending + /// the origin network (e.g. to prevent double spending) pub async fn lock_assertion( &mut self, request: impl tonic::IntoRequest, @@ -375,7 +375,7 @@ pub mod satp_server { /// Generated trait containing gRPC methods that should be implemented for use with SatpServer. #[async_trait] pub trait Satp: Send + Sync + 'static { - /// The sender gateway sends a TransferProposalClaims request to to initiate an asset transfer. + /// The sender gateway sends a TransferProposalClaims request to initiate an asset transfer. /// Depending on the proposal, multiple rounds of communication between the two gateways may happen. async fn transfer_proposal_claims( &self, @@ -413,7 +413,7 @@ pub mod satp_server { >; /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway /// declaring that the asset in question has been locked or escrowed by the sender gateway in - /// the origin network (e.g. to prevent double spending + /// the origin network (e.g. to prevent double spending) async fn lock_assertion( &self, request: tonic::Request, diff --git a/weaver/common/protos/driver/driver.proto b/weaver/common/protos/driver/driver.proto index 3e34263a73..400164bb11 100644 --- a/weaver/common/protos/driver/driver.proto +++ b/weaver/common/protos/driver/driver.proto @@ -16,6 +16,8 @@ message WriteExternalStateMessage { common.events.ContractTransaction ctx = 2; } +message PerformLockRequest {} + service DriverCommunication { // Data Sharing // the remote relay sends a RequestDriverState request to its driver with a @@ -34,4 +36,8 @@ service DriverCommunication { // Events Publication // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger rpc WriteExternalState(WriteExternalStateMessage) returns (common.ack.Ack) {} + + // As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + // to lock a specific asset + rpc PerformLock(PerformLockRequest) returns (common.ack.Ack) {} } \ No newline at end of file diff --git a/weaver/core/relay/driver/driver.rs b/weaver/core/relay/driver/driver.rs index d7106cbe15..7a5f23efb3 100644 --- a/weaver/core/relay/driver/driver.rs +++ b/weaver/core/relay/driver/driver.rs @@ -6,7 +6,7 @@ use weaverpb::common::query::Query; use weaverpb::common::events::EventSubscription; use weaverpb::common::state::{view_payload, Meta, meta, ViewPayload, View}; use weaverpb::driver::driver::driver_communication_server::{DriverCommunication, DriverCommunicationServer}; -use weaverpb::driver::driver::WriteExternalStateMessage; +use weaverpb::driver::driver::{WriteExternalStateMessage, PerformLockRequest}; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; @@ -204,6 +204,18 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(reply_error)); } + + async fn perform_lock(&self, request: Request) -> Result, Status> { + println!("Got a request from {:?}", request.remote_addr()); + println!("The asset has been locked"); + let request_id = "to_do".to_string(); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id, + message: "".to_string(), + }; + return Ok(Response::new(reply)); + } } fn send_driver_mock_state_helper(client: DataTransferClient, request_id: String) { diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 88f97cacf9..8139d52f5e 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -6,6 +6,7 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use tonic::Response; use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::state::{request_state, RequestState}; +use weaverpb::driver::driver::PerformLockRequest; use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ @@ -16,11 +17,13 @@ use weaverpb::relay::satp::{ use crate::db::Database; use crate::error::{self, Error}; use crate::relay_proto::LocationSegment; +use crate::services::helpers::get_driver_client; use super::constants::{ SATP_DB_PATH, SATP_REMOTE_REQUESTS_DB_PATH, SATP_REMOTE_REQUESTS_STATES_DB_PATH, SATP_REQUESTS_DB_PATH, SATP_REQUESTS_STATES_DB_PATH, }; +use super::types::Driver; // Sends a request to the receiving gateway pub fn spawn_send_transfer_proposal_claims_request( @@ -154,6 +157,8 @@ pub fn spawn_send_ack_commence_request( } pub fn spawn_send_perform_lock_request( + driver_info: Driver, + ack_commence_request: AckCommenceRequest, lock_assertion_request: LockAssertionRequest, relay_host: String, relay_port: String, @@ -167,11 +172,21 @@ pub fn spawn_send_perform_lock_request( "Locking the asset of the lock assertion request id: {:?}", request_id ); - // TODO - // Call the driver to check the asset status - // Subscribe to the status event + // TODO: pass the required info to lock the relevant asset + // Call the driver to lock the asset + let result = call_perform_lock(driver_info, ack_commence_request).await; + match result { + Ok(_) => { + println!("Ack Ok from driver\n") + } + Err(e) => { + println!("Error sending query to driver: {:?}\n", e); + // TODO: what to do in this case? + } + } + + // TODO: Subscribe to the status event // Once the asset is locked, call the lock_assertion endpoint - // log the results let result = call_lock_assertion( relay_host, relay_port, @@ -220,6 +235,30 @@ pub fn spawn_send_lock_assertion_broadcast_request( }); } +async fn call_perform_lock( + driver_info: Driver, + ack_commence_request: AckCommenceRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to lock the asset"); + let perform_lock_request = create_perform_lock_request(ack_commence_request); + let ack = client + .clone() + .perform_lock(perform_lock_request) + .await? + .into_inner(); + println!("Response ACK from driver={:?}\n", ack); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + // Call the transfer_commence endpoint on the receiver gateway pub async fn call_transfer_commence( relay_host: String, @@ -516,6 +555,12 @@ pub fn create_lock_assertion_receipt_request( return lock_assertion_receipt_request; } +pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> PerformLockRequest { + // TODO: remove hard coded values + let perform_lock_request = PerformLockRequest {}; + return perform_lock_request; +} + pub fn get_satp_requests_local_db(conf: Config) -> Database { let db = Database { db_path: format!( @@ -664,6 +709,11 @@ pub fn get_relay_from_lock_assertion_receipt( return ("localhost".to_string(), "9085".to_string()); } +pub fn get_driver_address_from_ack_commence(ack_commence_request: AckCommenceRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 71fe74b7d0..b5dd91c78f 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -8,17 +8,19 @@ use weaverpb::relay::satp::{ // Internal modules use crate::error::Error; +use crate::relay_proto::parse_address; use crate::services::satp_helper::{ create_ack_error_message, get_request_id_from_transfer_proposal_receipt, log_request_in_local_satp_db, log_request_in_remote_satp_db, }; +use super::helpers::get_driver; // external modules use super::satp_helper::{ create_ack_commence_request, create_lock_assertion_receipt_request, create_lock_assertion_request, create_transfer_commence_request, - create_transfer_proposal_receipt_request, get_relay_from_ack_commence, - get_relay_from_lock_assertion, get_relay_from_transfer_commence, + create_transfer_proposal_receipt_request, get_driver_address_from_ack_commence, + get_relay_from_ack_commence, get_relay_from_lock_assertion, get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, spawn_send_lock_assertion_broadcast_request, @@ -713,23 +715,40 @@ fn send_perform_lock_request( let (relay_host, relay_port) = get_relay_from_ack_commence(ack_commence_request.clone()); let (use_tls, relay_tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let perfrom_lock_request = create_lock_assertion_request(ack_commence_request.clone()); - - spawn_send_perform_lock_request( - perfrom_lock_request, - relay_host, - relay_port, - use_tls, - relay_tlsca_cert_path, - conf, - ); - - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request_id.to_string(), - message: "Ack of the ack commence request".to_string(), - }; - return Ok(reply); + let lock_assertion_request = create_lock_assertion_request(ack_commence_request.clone()); + let driver_address = get_driver_address_from_ack_commence(ack_commence_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); + match result { + Ok(driver_info) => { + spawn_send_perform_lock_request( + driver_info, + ack_commence_request, + lock_assertion_request, + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the ack commence request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the ack commence request failed. Driver not found {:?}", + e + ), + }); + } + } } fn send_lock_assertion_broadcast_request( From bc6fa77bd62b304bf5b6e3ba216f85bb0f932d22 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Fri, 4 Aug 2023 08:19:22 +0100 Subject: [PATCH 17/59] corrected some variable names --- .../relay/src/services/network_service.rs | 16 ++++----- weaver/core/relay/src/services/satp_helper.rs | 36 +++++++++---------- .../core/relay/src/services/satp_service.rs | 24 ++++++------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 10ae6a7c72..4d1e4b365f 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -593,7 +593,7 @@ impl Network for NetworkService { let (relay_host, relay_port) = get_relay_from_transfer_proposal_claims( transfer_proposal_claims_request.clone(), ); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); // TODO: verify that host and port are valid @@ -603,7 +603,7 @@ impl Network for NetworkService { relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); // Send Ack back to network while request is happening in a thread @@ -805,12 +805,12 @@ fn spawn_send_request( // Iterate through the relay entries in the configuration to find a match let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; - let mut relay_tlsca_cert_path = "".to_string(); + let mut tlsca_cert_path = "".to_string(); for (_relay_name, relay_spec) in relays_table { let relay_uri = relay_spec.clone().try_into::().unwrap(); if relay_host == relay_uri.hostname && relay_port == relay_uri.port { relay_tls = relay_uri.tls; - relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + tlsca_cert_path = relay_uri.tlsca_cert_path; } } @@ -821,7 +821,7 @@ fn spawn_send_request( network_query, request_id.clone(), relay_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), ) .await; println!("Received Ack from remote relay: {:?}\n", result); @@ -944,12 +944,12 @@ fn spawn_send_event_subscription_request( // Iterate through the relay entries in the configuration to find a match let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; - let mut relay_tlsca_cert_path = "".to_string(); + let mut tlsca_cert_path = "".to_string(); for (_relay_name, relay_spec) in relays_table { let relay_uri = relay_spec.clone().try_into::().unwrap(); if relay_host == relay_uri.hostname && relay_port == relay_uri.port { relay_tls = relay_uri.tls; - relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + tlsca_cert_path = relay_uri.tlsca_cert_path; } } @@ -958,7 +958,7 @@ fn spawn_send_event_subscription_request( relay_port, event_subscription, relay_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), ) .await; println!("Received Ack from remote relay: {:?}\n", result); diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 8139d52f5e..ea7258ec2d 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -31,7 +31,7 @@ pub fn spawn_send_transfer_proposal_claims_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { println!( @@ -50,7 +50,7 @@ pub fn spawn_send_transfer_proposal_claims_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), transfer_proposal_claims_request.clone(), ) .await; @@ -67,7 +67,7 @@ pub fn spawn_send_transfer_commence_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { println!( @@ -85,7 +85,7 @@ pub fn spawn_send_transfer_commence_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), transfer_commence_request.clone(), ) .await; @@ -101,7 +101,7 @@ pub fn spawn_send_transfer_proposal_receipt_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { @@ -116,7 +116,7 @@ pub fn spawn_send_transfer_proposal_receipt_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), transfer_proposal_receipt_request.clone(), ) .await; @@ -132,7 +132,7 @@ pub fn spawn_send_ack_commence_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { @@ -145,7 +145,7 @@ pub fn spawn_send_ack_commence_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), ack_commence_request.clone(), ) .await; @@ -163,7 +163,7 @@ pub fn spawn_send_perform_lock_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { @@ -177,10 +177,10 @@ pub fn spawn_send_perform_lock_request( let result = call_perform_lock(driver_info, ack_commence_request).await; match result { Ok(_) => { - println!("Ack Ok from driver\n") + println!("Perform lock request sent to driver\n") } Err(e) => { - println!("Error sending query to driver: {:?}\n", e); + println!("Error sending perform lock request to driver: {:?}\n", e); // TODO: what to do in this case? } } @@ -191,7 +191,7 @@ pub fn spawn_send_perform_lock_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), lock_assertion_request.clone(), ) .await; @@ -208,7 +208,7 @@ pub fn spawn_send_lock_assertion_broadcast_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { @@ -223,7 +223,7 @@ pub fn spawn_send_lock_assertion_broadcast_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), lock_assertion_receipt_request.clone(), ) .await; @@ -247,7 +247,7 @@ async fn call_perform_lock( .perform_lock(perform_lock_request) .await? .into_inner(); - println!("Response ACK from driver={:?}\n", ack); + println!("Response ACK from driver to perform lock {:?}\n", ack); let status = ack::Status::from_i32(ack.status) .ok_or(Error::Simple("Status from Driver error".to_string()))?; match status { @@ -717,15 +717,15 @@ pub fn get_driver_address_from_ack_commence(ack_commence_request: AckCommenceReq pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; - let mut relay_tlsca_cert_path = "".to_string(); + let mut tlsca_cert_path = "".to_string(); for (_relay_name, relay_spec) in relays_table { let relay_uri = relay_spec.clone().try_into::().unwrap(); if relay_host == relay_uri.hostname && relay_port == relay_uri.port { relay_tls = relay_uri.tls; - relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + tlsca_cert_path = relay_uri.tlsca_cert_path; } } - (relay_tls, relay_tlsca_cert_path) + (relay_tls, tlsca_cert_path) } fn create_client_address(relay_host: String, relay_port: String) -> String { diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index b5dd91c78f..a6031eaf9a 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -603,7 +603,7 @@ fn send_transfer_proposal_receipt_request( get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); let (relay_host, relay_port) = get_relay_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let transfer_proposal_receipt_request = create_transfer_proposal_receipt_request(transfer_proposal_claims_request.clone()); @@ -613,7 +613,7 @@ fn send_transfer_proposal_receipt_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -632,7 +632,7 @@ fn send_transfer_commence_request( get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); let (relay_host, relay_port) = get_relay_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let transfer_commence_request = create_transfer_commence_request(transfer_proposal_receipt_request.clone()); @@ -642,7 +642,7 @@ fn send_transfer_commence_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -660,7 +660,7 @@ fn send_ack_commence_request( let request_id = &transfer_commence_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_transfer_commence(transfer_commence_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let ack_commence_request = create_ack_commence_request(transfer_commence_request.clone()); @@ -669,7 +669,7 @@ fn send_ack_commence_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -686,7 +686,7 @@ fn send_lock_assertion_receipt_request( ) -> Result { let request_id = &lock_assertion_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let lock_assertion_receipt_request = create_lock_assertion_receipt_request(lock_assertion_request.clone()); @@ -696,7 +696,7 @@ fn send_lock_assertion_receipt_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -713,7 +713,7 @@ fn send_perform_lock_request( ) -> Result { let request_id = &ack_commence_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_ack_commence(ack_commence_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let lock_assertion_request = create_lock_assertion_request(ack_commence_request.clone()); let driver_address = get_driver_address_from_ack_commence(ack_commence_request.clone()); @@ -728,7 +728,7 @@ fn send_perform_lock_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -757,7 +757,7 @@ fn send_lock_assertion_broadcast_request( ) -> Result { let request_id = &lock_assertion_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let lock_assertion_receipt_request = create_lock_assertion_receipt_request(lock_assertion_request.clone()); @@ -767,7 +767,7 @@ fn send_lock_assertion_broadcast_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { From 2ae61f958980230bac111292f12b4adcb6edfac0 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Wed, 9 Aug 2023 10:26:33 +0100 Subject: [PATCH 18/59] Added the endpoints corresponding to the steps 3.1 to 3.9 --- .../protos-rs/pkg/src/generated/relay.satp.rs | 398 ++++++++++++ weaver/common/protos/relay/satp.proto | 40 ++ weaver/core/relay/src/services/satp_helper.rs | 363 ++++++++++- .../core/relay/src/services/satp_service.rs | 571 +++++++++++++++++- 4 files changed, 1360 insertions(+), 12 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index 743a57a40b..32e96b36e1 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -152,6 +152,61 @@ pub struct LockAssertionReceiptRequest { #[prost(string, tag = "8")] pub server_signature: ::prost::alloc::string::String, } +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommitPrepareRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommitReadyRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommitFinalAssertionRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AckFinalReceiptRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransferCompletedRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} /// Generated client implementations. pub mod satp_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] @@ -366,6 +421,116 @@ pub mod satp_client { ); self.inner.unary(request.into_request(), path, codec).await } + pub async fn commit_prepare( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/CommitPrepare", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn commit_ready( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/CommitReady", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn commit_final_assertion( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/CommitFinalAssertion", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn ack_final_receipt( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/AckFinalReceipt", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn transfer_completed( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/TransferCompleted", + ); + self.inner.unary(request.into_request(), path, codec).await + } } } /// Generated server implementations. @@ -430,6 +595,41 @@ pub mod satp_server { tonic::Response, tonic::Status, >; + async fn commit_prepare( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn commit_ready( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn commit_final_assertion( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn ack_final_receipt( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn transfer_completed( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct SatpServer { @@ -730,6 +930,204 @@ pub mod satp_server { }; Box::pin(fut) } + "/relay.satp.SATP/CommitPrepare" => { + #[allow(non_camel_case_types)] + struct CommitPrepareSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for CommitPrepareSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).commit_prepare(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommitPrepareSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/CommitReady" => { + #[allow(non_camel_case_types)] + struct CommitReadySvc(pub Arc); + impl tonic::server::UnaryService + for CommitReadySvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).commit_ready(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommitReadySvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/CommitFinalAssertion" => { + #[allow(non_camel_case_types)] + struct CommitFinalAssertionSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for CommitFinalAssertionSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).commit_final_assertion(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommitFinalAssertionSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/AckFinalReceipt" => { + #[allow(non_camel_case_types)] + struct AckFinalReceiptSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for AckFinalReceiptSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).ack_final_receipt(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = AckFinalReceiptSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/TransferCompleted" => { + #[allow(non_camel_case_types)] + struct TransferCompletedSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for TransferCompletedSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).transfer_completed(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = TransferCompletedSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( diff --git a/weaver/common/protos/relay/satp.proto b/weaver/common/protos/relay/satp.proto index 66d2bf7073..595f91d7fb 100644 --- a/weaver/common/protos/relay/satp.proto +++ b/weaver/common/protos/relay/satp.proto @@ -38,6 +38,16 @@ service SATP { // The receiver gateway sends a LockAssertionReceipt request to the sender gateway to indicate acceptance // of the claim(s) delivered by the sender gateway in the previous message rpc LockAssertionReceipt(LockAssertionReceiptRequest) returns (common.ack.Ack) {}; + + rpc CommitPrepare(CommitPrepareRequest) returns (common.ack.Ack) {}; + + rpc CommitReady(CommitReadyRequest) returns (common.ack.Ack) {}; + + rpc CommitFinalAssertion(CommitFinalAssertionRequest) returns (common.ack.Ack) {}; + + rpc AckFinalReceipt(AckFinalReceiptRequest) returns (common.ack.Ack) {}; + + rpc TransferCompleted(TransferCompletedRequest) returns (common.ack.Ack) {}; } message TransferProposalClaimsRequest { @@ -118,4 +128,34 @@ message LockAssertionReceiptRequest { string hash_prev_message = 6; string server_transfer_number = 7; string server_signature = 8; +} + +message CommitPrepareRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message CommitReadyRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message CommitFinalAssertionRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message AckFinalReceiptRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message TransferCompletedRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; } \ No newline at end of file diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index ea7258ec2d..51141e332a 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -10,8 +10,9 @@ use weaverpb::driver::driver::PerformLockRequest; use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ - AckCommenceRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, - TransferProposalClaimsRequest, TransferProposalReceiptRequest, + AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, + CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, + TransferCompletedRequest, TransferProposalClaimsRequest, TransferProposalReceiptRequest, }; use crate::db::Database; @@ -235,6 +236,178 @@ pub fn spawn_send_lock_assertion_broadcast_request( }); } +// Sends a request to the receiving gateway +pub fn spawn_send_commit_prepare_request( + commit_prepare_request: CommitPrepareRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + println!( + "Sending commit prepare request to receiver gateway: {:?}:{:?}", + relay_host, relay_port + ); + // Spawning new thread to make the call_commit_prepare to receiver gateway + tokio::spawn(async move { + let request_id = commit_prepare_request.session_id.to_string(); + println!( + "Sending commit prepare request to receiver gateway: Request ID = {:?}", + request_id + ); + let result = call_commit_prepare( + relay_host, + relay_port, + use_tls, + tlsca_cert_path.to_string(), + commit_prepare_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_create_asset_request( + commit_ready_request: CommitReadyRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = commit_ready_request.session_id.to_string(); + println!( + "Creating the asset corresponding to the commit ready request {:?}", + request_id + ); + // TODO + // Creating the asset in the target network + // Subscribe to the status event + // Once the message is broadcast, call the call_commit_ready endpoint + // log the results + let result = call_commit_ready( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + commit_ready_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = commit_ready_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_assign_asset_request( + ack_final_receipt_request: AckFinalReceiptRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = ack_final_receipt_request.session_id.to_string(); + println!( + "Assigning the asset corresponding to the commit final assertion request {:?}", + request_id + ); + // TODO + // Assigning the asset in the target network + // Once the asset is assigned, call the call_ack_final_receipt endpoint + // log the results + let result = call_ack_final_receipt( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + ack_final_receipt_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = ack_final_receipt_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_ack_final_receipt_broadcast_request( + transfer_completed_request: TransferCompletedRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = transfer_completed_request.session_id.to_string(); + println!( + "Acknowledge final receipt broadcast of the transfer completed request {:?}", + request_id + ); + // TODO + // Ack final receipt broadcast + // Once the broadcast is done, call the call_transfer_completed endpoint + // log the results + let result = call_transfer_completed( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + transfer_completed_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = transfer_completed_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_extinguish_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = commit_final_assertion_request.session_id.to_string(); + println!( + "Extinguishing the asset corresponding to the commit final assertion request {:?}", + request_id + ); + // TODO + // Assigning the asset in the target network + // Once the asset is assigned, call the call_ack_final_receipt endpoint + // log the results + let result = call_commit_final_assertion_receipt( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + commit_final_assertion_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = commit_final_assertion_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + async fn call_perform_lock( driver_info: Driver, ack_commence_request: AckCommenceRequest, @@ -379,6 +552,106 @@ pub async fn call_lock_assertion_receipt( Ok(response) } +// Call the call_commit_ready endpoint on the sending gateway +pub async fn call_commit_prepare( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + commit_prepare_request: CommitPrepareRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the commit prepare request: {:?}", + commit_prepare_request.clone() + ); + let response = satp_client + .commit_prepare(commit_prepare_request.clone()) + .await?; + Ok(response) +} + +// Call the call_commit_ready endpoint on the sending gateway +pub async fn call_commit_ready( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + commit_ready_request: CommitReadyRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the commit ready request: {:?}", + commit_ready_request.clone() + ); + let response = satp_client + .commit_ready(commit_ready_request.clone()) + .await?; + Ok(response) +} + +// Call the call_ack_final_receipt endpoint on the sending gateway +pub async fn call_ack_final_receipt( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + ack_final_receipt_request: AckFinalReceiptRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the ack final receipt request: {:?}", + ack_final_receipt_request.clone() + ); + let response = satp_client + .ack_final_receipt(ack_final_receipt_request.clone()) + .await?; + Ok(response) +} + +// Call the call_transfer_completed endpoint on the sending gateway +pub async fn call_transfer_completed( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + transfer_completed_request: TransferCompletedRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the transfer completed request: {:?}", + transfer_completed_request.clone() + ); + let response = satp_client + .transfer_completed(transfer_completed_request.clone()) + .await?; + Ok(response) +} + +// Call the call_commit_final_assertion_receipt endpoint on the sending gateway +pub async fn call_commit_final_assertion_receipt( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the commit final assertion request: {:?}", + commit_final_assertion_request.clone() + ); + let response = satp_client + .commit_final_assertion(commit_final_assertion_request.clone()) + .await?; + Ok(response) +} + pub fn log_request_result_in_local_satp_db( request_id: &String, result: Result, Box>, @@ -555,6 +828,66 @@ pub fn create_lock_assertion_receipt_request( return lock_assertion_receipt_request; } +pub fn create_commit_prepare_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> CommitPrepareRequest { + // TODO: remove hard coded values + let commit_prepare_request = CommitPrepareRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_prepare_request; +} + +pub fn create_commit_ready_request( + commit_prepare_request: CommitPrepareRequest, +) -> CommitReadyRequest { + // TODO: remove hard coded values + let commit_ready_request = CommitReadyRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_ready_request; +} + +pub fn create_commit_final_assertion_request( + commit_ready_request: CommitReadyRequest, +) -> CommitFinalAssertionRequest { + // TODO: remove hard coded values + let commit_final_assertion_request = CommitFinalAssertionRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_final_assertion_request; +} + +pub fn create_ack_final_receipt_request( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> AckFinalReceiptRequest { + // TODO: remove hard coded values + let ack_final_receipt_request = AckFinalReceiptRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return ack_final_receipt_request; +} + +pub fn create_transfer_completed_request( + ack_final_receipt_request: AckFinalReceiptRequest, +) -> TransferCompletedRequest { + // TODO: remove hard coded values + let transfer_completed_request = TransferCompletedRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return transfer_completed_request; +} + pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> PerformLockRequest { // TODO: remove hard coded values let perform_lock_request = PerformLockRequest {}; @@ -709,6 +1042,32 @@ pub fn get_relay_from_lock_assertion_receipt( return ("localhost".to_string(), "9085".to_string()); } +pub fn get_relay_from_commit_prepare( + commit_prepare_request: CommitPrepareRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_commit_ready(commit_ready_request: CommitReadyRequest) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_commit_final_assertion( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_ack_final_receipt( + ack_final_receipt_request: AckFinalReceiptRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + pub fn get_driver_address_from_ack_commence(ack_commence_request: AckCommenceRequest) -> String { // TODO return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index a6031eaf9a..f154cce560 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -2,8 +2,9 @@ use weaverpb::common::ack::{ack, Ack}; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{ - AckCommenceRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, - TransferProposalClaimsRequest, TransferProposalReceiptRequest, + AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, + CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, + TransferCompletedRequest, TransferProposalClaimsRequest, TransferProposalReceiptRequest, }; // Internal modules @@ -17,15 +18,22 @@ use crate::services::satp_helper::{ use super::helpers::get_driver; // external modules use super::satp_helper::{ - create_ack_commence_request, create_lock_assertion_receipt_request, + create_ack_commence_request, create_ack_final_receipt_request, + create_commit_final_assertion_request, create_commit_prepare_request, + create_commit_ready_request, create_lock_assertion_receipt_request, create_lock_assertion_request, create_transfer_commence_request, - create_transfer_proposal_receipt_request, get_driver_address_from_ack_commence, - get_relay_from_ack_commence, get_relay_from_lock_assertion, get_relay_from_transfer_commence, + create_transfer_completed_request, create_transfer_proposal_receipt_request, + get_driver_address_from_ack_commence, get_relay_from_ack_commence, + get_relay_from_ack_final_receipt, get_relay_from_commit_final_assertion, + get_relay_from_commit_prepare, get_relay_from_commit_ready, get_relay_from_lock_assertion, + get_relay_from_lock_assertion_receipt, get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, - spawn_send_ack_commence_request, spawn_send_lock_assertion_broadcast_request, - spawn_send_perform_lock_request, spawn_send_transfer_commence_request, - spawn_send_transfer_proposal_receipt_request, + spawn_send_ack_commence_request, spawn_send_ack_final_receipt_broadcast_request, + spawn_send_assign_asset_request, spawn_send_commit_prepare_request, + spawn_send_create_asset_request, spawn_send_extinguish_request, + spawn_send_lock_assertion_broadcast_request, spawn_send_perform_lock_request, + spawn_send_transfer_commence_request, spawn_send_transfer_proposal_receipt_request, }; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; @@ -341,6 +349,248 @@ impl Satp for SatpService { } } } + + async fn commit_prepare( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got commit prepare request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let commit_prepare_request = request.into_inner().clone(); + let request_id = commit_prepare_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &commit_prepare_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored CommitPrepareRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing CommitPrepareRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_commit_prepare_request(commit_prepare_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!("Sending Ack of commit prepare request back: {:?}\n", reply); + reply + } + Err(e) => { + let error_message = "Commit prepare failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn commit_ready( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got commit ready request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let commit_ready_request = request.into_inner().clone(); + let request_id = commit_ready_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &commit_ready_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored CommitReadyRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing CommitReadyRequest in local satp_db for request_id".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_commit_ready_request(commit_ready_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!("Sending Ack of commit ready request back: {:?}\n", reply); + reply + } + Err(e) => { + let error_message = "Commit ready failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn commit_final_assertion( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got commit final assertion request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let commit_final_assertion_request = request.into_inner().clone(); + let request_id = commit_final_assertion_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = log_request_in_local_satp_db( + &request_id, + &commit_final_assertion_request, + conf.clone(), + ); + match request_logged { + Ok(_) => { + println!( + "Successfully stored CommitFinalAssertionRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing CommitFinalAssertionRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_commit_final_assertion_request(commit_final_assertion_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of commit final assertion request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Commit final assertion failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn ack_final_receipt( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got commit final assertion request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let ack_final_receipt_request = request.into_inner().clone(); + let request_id = ack_final_receipt_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &ack_final_receipt_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored AckFinalReceiptRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing AckFinalReceiptRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_ack_final_receipt_request(ack_final_receipt_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of ack final receipt request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Ack final receipt failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn transfer_completed( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got commit final assertion request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let transfer_completed_request = request.into_inner().clone(); + let request_id = transfer_completed_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &transfer_completed_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored TransferCompletedRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing TransferCompletedRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Transfer Completed request".to_string(), + }; + return Ok(Response::new(reply)); + } } pub fn process_transfer_proposal_claims_request( @@ -595,6 +845,147 @@ pub fn process_lock_assertion_receipt_request( } } +pub fn process_commit_prepare_request( + commit_prepare_request: CommitPrepareRequest, + conf: config::Config, +) -> Result { + let request_id = commit_prepare_request.session_id.to_string(); + let is_valid_request = is_valid_commit_prepare_request(commit_prepare_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The commit prepare request is valid\n"); + match send_commit_ready_request(commit_prepare_request, conf) { + Ok(ack) => { + println!("Ack commit prepare request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: commit prepare request failed. {:?}", e), + }); + } + } + } else { + println!("The commit prepare request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The commit prepare request is invalid".to_string(), + }); + } +} + +pub fn process_commit_ready_request( + commit_ready_request: CommitReadyRequest, + conf: config::Config, +) -> Result { + let request_id = commit_ready_request.session_id.to_string(); + let is_valid_request = is_valid_commit_ready_request(commit_ready_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The commit ready request is valid\n"); + match send_commit_final_assertion_request(commit_ready_request, conf) { + Ok(ack) => { + println!("Ack commit ready request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: commit ready request failed. {:?}", e), + }); + } + } + } else { + println!("The commit ready request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The commit ready request is invalid".to_string(), + }); + } +} + +pub fn process_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + conf: config::Config, +) -> Result { + let request_id = commit_final_assertion_request.session_id.to_string(); + let is_valid_request = + is_valid_commit_final_assertion_request(commit_final_assertion_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The commit final assertion request is valid\n"); + match send_ack_final_receipt_request(commit_final_assertion_request, conf) { + Ok(ack) => { + println!("Ack commit final assertion request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: commit final assertion request failed. {:?}", e), + }); + } + } + } else { + println!("The commit final assertion request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The commit final assertion request is invalid".to_string(), + }); + } +} + +pub fn process_ack_final_receipt_request( + ack_final_receipt_request: AckFinalReceiptRequest, + conf: config::Config, +) -> Result { + let request_id = ack_final_receipt_request.session_id.to_string(); + let is_valid_request = is_valid_ack_final_receipt_request(ack_final_receipt_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The ack final receipt request is valid\n"); + match send_transfer_completed_request(ack_final_receipt_request, conf) { + Ok(ack) => { + println!("Ack ack final receipt request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: ack final receipt request failed. {:?}", e), + }); + } + } + } else { + println!("The ack final receipt request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The ack final receipt request is invalid".to_string(), + }); + } +} + fn send_transfer_proposal_receipt_request( transfer_proposal_claims_request: TransferProposalClaimsRequest, conf: config::Config, @@ -782,12 +1173,143 @@ fn send_commit_prepare_request( lock_assertion_receipt_request: LockAssertionReceiptRequest, conf: config::Config, ) -> Result { - // TODO let request_id = &lock_assertion_receipt_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_lock_assertion_receipt(lock_assertion_receipt_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let commit_prepare_request = + create_commit_prepare_request(lock_assertion_receipt_request.clone()); + + spawn_send_commit_prepare_request( + commit_prepare_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), - message: "Ack of the Lock Assertion Receipt request".to_string(), + message: "Ack of the Lock Assertion request".to_string(), + }; + return Ok(reply); +} + +fn send_commit_ready_request( + commit_prepare_request: CommitPrepareRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_prepare_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let commit_ready_request = create_commit_ready_request(commit_prepare_request.clone()); + + spawn_send_create_asset_request( + commit_ready_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_commit_final_assertion_request( + commit_ready_request: CommitReadyRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_ready_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_commit_ready(commit_ready_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let commit_final_assertion_request = + create_commit_final_assertion_request(commit_ready_request.clone()); + + spawn_send_extinguish_request( + commit_final_assertion_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_ack_final_receipt_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_final_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_commit_final_assertion(commit_final_assertion_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let ack_final_receipt_request = + create_ack_final_receipt_request(commit_final_assertion_request.clone()); + + spawn_send_assign_asset_request( + ack_final_receipt_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_transfer_completed_request( + ack_final_receipt_request: AckFinalReceiptRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &ack_final_receipt_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let transfer_completed_request = + create_transfer_completed_request(ack_final_receipt_request.clone()); + + spawn_send_ack_final_receipt_broadcast_request( + transfer_completed_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), }; return Ok(reply); } @@ -827,3 +1349,32 @@ fn is_valid_lock_assertion_receipt_request( //TODO true } + +fn is_valid_commit_prepare_request(commit_prepare_request: CommitPrepareRequest) -> bool { + //TODO + true +} + +fn is_valid_commit_ready_request(commit_ready_request: CommitReadyRequest) -> bool { + //TODO + true +} + +fn is_valid_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> bool { + //TODO + true +} + +fn is_valid_ack_final_receipt_request(ack_final_receipt_request: AckFinalReceiptRequest) -> bool { + //TODO + true +} + +fn is_valid_transfer_completed_request( + transfer_completed_request: TransferCompletedRequest, +) -> bool { + //TODO + true +} From 2e38595c1ee5d3b6008bdb4bcdc0413dedb84cc9 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 14 Aug 2023 10:48:31 +0100 Subject: [PATCH 19/59] Implemented the step 2.1B so that the driver call the gateway to update the asset status --- .../pkg/src/generated/driver.driver.rs | 5 +- .../protos-rs/pkg/src/generated/relay.satp.rs | 90 +++++++++ weaver/common/protos/driver/driver.proto | 4 +- weaver/common/protos/relay/satp.proto | 13 ++ weaver/core/relay/driver/driver.rs | 177 ++++++++++++++--- weaver/core/relay/src/services/satp_helper.rs | 69 ++++--- .../core/relay/src/services/satp_service.rs | 180 +++++++++++++----- 7 files changed, 432 insertions(+), 106 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs index 011b4085a0..15de731bd4 100644 --- a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs +++ b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs @@ -11,7 +11,10 @@ pub struct WriteExternalStateMessage { #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct PerformLockRequest {} +pub struct PerformLockRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} /// Generated client implementations. pub mod driver_communication_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index 32e96b36e1..c1b94e14b9 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -107,6 +107,27 @@ pub struct AckCommenceRequest { #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct SendAssetStatusRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub hash_prev_message: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub server_transfer_number: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub server_signature: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct LockAssertionRequest { #[prost(string, tag = "1")] pub message_type: ::prost::alloc::string::String, @@ -372,6 +393,28 @@ pub mod satp_client { ); self.inner.unary(request.into_request(), path, codec).await } + pub async fn send_asset_status( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/SendAssetStatus", + ); + self.inner.unary(request.into_request(), path, codec).await + } /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway /// declaring that the asset in question has been locked or escrowed by the sender gateway in /// the origin network (e.g. to prevent double spending) @@ -576,6 +619,13 @@ pub mod satp_server { tonic::Response, tonic::Status, >; + async fn send_asset_status( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway /// declaring that the asset in question has been locked or escrowed by the sender gateway in /// the origin network (e.g. to prevent double spending) @@ -850,6 +900,46 @@ pub mod satp_server { }; Box::pin(fut) } + "/relay.satp.SATP/SendAssetStatus" => { + #[allow(non_camel_case_types)] + struct SendAssetStatusSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for SendAssetStatusSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).send_asset_status(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = SendAssetStatusSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/relay.satp.SATP/LockAssertion" => { #[allow(non_camel_case_types)] struct LockAssertionSvc(pub Arc); diff --git a/weaver/common/protos/driver/driver.proto b/weaver/common/protos/driver/driver.proto index 400164bb11..db1a1112b9 100644 --- a/weaver/common/protos/driver/driver.proto +++ b/weaver/common/protos/driver/driver.proto @@ -16,7 +16,9 @@ message WriteExternalStateMessage { common.events.ContractTransaction ctx = 2; } -message PerformLockRequest {} +message PerformLockRequest { + string session_id = 1; +} service DriverCommunication { // Data Sharing diff --git a/weaver/common/protos/relay/satp.proto b/weaver/common/protos/relay/satp.proto index 595f91d7fb..d7dd1b63c4 100644 --- a/weaver/common/protos/relay/satp.proto +++ b/weaver/common/protos/relay/satp.proto @@ -30,6 +30,8 @@ service SATP { // Stage 2 endpoints + rpc SendAssetStatus(SendAssetStatusRequest) returns (common.ack.Ack) {}; + // The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway // declaring that the asset in question has been locked or escrowed by the sender gateway in // the origin network (e.g. to prevent double spending) @@ -105,6 +107,17 @@ message AckCommenceRequest { string server_signature = 8; } +message SendAssetStatusRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_prev_message = 6; + string server_transfer_number = 7; + string server_signature = 8; +} + message LockAssertionRequest { string message_type = 1; string session_id = 2; diff --git a/weaver/core/relay/driver/driver.rs b/weaver/core/relay/driver/driver.rs index 7a5f23efb3..34b78f6ec5 100644 --- a/weaver/core/relay/driver/driver.rs +++ b/weaver/core/relay/driver/driver.rs @@ -2,11 +2,13 @@ // Internal modules use weaverpb::common::ack::{ack, Ack}; -use weaverpb::common::query::Query; use weaverpb::common::events::EventSubscription; -use weaverpb::common::state::{view_payload, Meta, meta, ViewPayload, View}; -use weaverpb::driver::driver::driver_communication_server::{DriverCommunication, DriverCommunicationServer}; -use weaverpb::driver::driver::{WriteExternalStateMessage, PerformLockRequest}; +use weaverpb::common::query::Query; +use weaverpb::common::state::{meta, view_payload, Meta, View, ViewPayload}; +use weaverpb::driver::driver::driver_communication_server::{ + DriverCommunication, DriverCommunicationServer, +}; +use weaverpb::driver::driver::{PerformLockRequest, WriteExternalStateMessage}; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; @@ -18,8 +20,10 @@ use std::net::ToSocketAddrs; use std::thread::sleep; use std::time; use tokio::sync::RwLock; -use tonic::transport::{Identity, Server, ServerTlsConfig, Certificate, Channel, ClientTlsConfig}; +use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity, Server, ServerTlsConfig}; use tonic::{Request, Response, Status}; +use weaverpb::relay::satp::satp_client::SatpClient; +use weaverpb::relay::satp::SendAssetStatusRequest; pub struct DriverCommunicationService { pub config_lock: RwLock, @@ -38,7 +42,7 @@ impl DriverCommunication for DriverCommunicationService { println!("Got a request from {:?}", request.remote_addr()); let query = request.into_inner().clone(); let request_id = query.request_id.to_string(); - + let relays_table = self .config_lock .read() @@ -48,7 +52,9 @@ impl DriverCommunication for DriverCommunicationService { let relay_uri = relays_table .get(&query.requesting_relay.to_string()) .expect("Requesting relay not found in config file relays table"); - let uri = relay_uri.clone().try_into::() + let uri = relay_uri + .clone() + .try_into::() .expect("Syntax for relays table in config file not correct"); let relay_port = uri.port.to_string(); @@ -56,7 +62,7 @@ impl DriverCommunication for DriverCommunicationService { let use_tls = uri.tls; let tlsca_cert_path = uri.tlsca_cert_path.to_string(); let client_addr = format!("http://{}:{}", relay_hostname, relay_port); - + if use_tls { let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); let ca = Certificate::from_pem(pem); @@ -65,8 +71,13 @@ impl DriverCommunication for DriverCommunicationService { .ca_certificate(ca) .domain_name(relay_hostname); - let channel = Channel::from_shared(client_addr.to_string()).unwrap() - .tls_config(tls).expect(&format!("Error in TLS configuration for client: {}", client_addr.to_string())) + let channel = Channel::from_shared(client_addr.to_string()) + .unwrap() + .tls_config(tls) + .expect(&format!( + "Error in TLS configuration for client: {}", + client_addr.to_string() + )) .connect() .await .unwrap(); @@ -95,8 +106,14 @@ impl DriverCommunication for DriverCommunicationService { return Ok(Response::new(reply)); } - async fn subscribe_event(&self, request: Request) -> Result, Status> { - println!("Driver: Got a event subscription request from {:?}", request.remote_addr()); + async fn subscribe_event( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Driver: Got a event subscription request from {:?}", + request.remote_addr() + ); let into_inner = request.into_inner().clone(); let query = into_inner.query.clone().expect(""); let request_id = query.clone().request_id.to_string(); @@ -110,9 +127,11 @@ impl DriverCommunication for DriverCommunicationService { let relay_uri = relays_table .get(&query.requesting_relay.to_string()) .expect("Requesting relay not found in config file relays table"); - let uri = relay_uri.clone().try_into::() + let uri = relay_uri + .clone() + .try_into::() .expect("Syntax for relays table in config file not correct"); - + let relay_port = uri.port.to_string(); let relay_hostname = uri.hostname.to_string(); let use_tls = uri.tls; @@ -127,8 +146,13 @@ impl DriverCommunication for DriverCommunicationService { .ca_certificate(ca) .domain_name(relay_hostname); - let channel = Channel::from_shared(client_addr.to_string()).unwrap() - .tls_config(tls).expect(&format!("Error in TLS configuration for client: {}", client_addr.to_string())) + let channel = Channel::from_shared(client_addr.to_string()) + .unwrap() + .tls_config(tls) + .expect(&format!( + "Error in TLS configuration for client: {}", + client_addr.to_string() + )) .connect() .await .unwrap(); @@ -157,7 +181,10 @@ impl DriverCommunication for DriverCommunicationService { return Ok(Response::new(reply)); } - async fn request_signed_event_subscription_query(&self, request: Request) -> Result, Status> { + async fn request_signed_event_subscription_query( + &self, + request: Request, + ) -> Result, Status> { let received_query = request.into_inner().clone().query.expect("Err"); let signed_query: Query = Query { policy: received_query.policy, @@ -173,7 +200,10 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(signed_query)); } - async fn write_external_state(&self, request: Request) -> Result, Status> { + async fn write_external_state( + &self, + request: Request, + ) -> Result, Status> { let view_payload = request.into_inner().view_payload.expect("Error"); let request_id = view_payload.clone().request_id.to_string(); match view_payload.state { @@ -194,7 +224,7 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(reply)); } - } + }, None => {} } let reply_error = Ack { @@ -204,11 +234,72 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(reply_error)); } - - async fn perform_lock(&self, request: Request) -> Result, Status> { + + async fn perform_lock( + &self, + request: Request, + ) -> Result, Status> { println!("Got a request from {:?}", request.remote_addr()); + let perform_lock_request = request.into_inner().clone(); println!("The asset has been locked"); - let request_id = "to_do".to_string(); + let request_id = perform_lock_request.session_id.to_string(); + + let relays_table = self + .config_lock + .read() + .await + .get_table("relays") + .expect("No relays table in config file"); + let requesting_relay = get_relay_from_perform_lock(perform_lock_request); + let relay_uri = relays_table + .get(&requesting_relay.to_string()) + .expect("Requesting relay not found in config file relays table"); + let uri = relay_uri + .clone() + .try_into::() + .expect("Syntax for relays table in config file not correct"); + + let relay_port = uri.port.to_string(); + let relay_hostname = uri.hostname.to_string(); + let use_tls = uri.tls; + let tlsca_cert_path = uri.tlsca_cert_path.to_string(); + let client_addr = format!("http://{}:{}", relay_hostname, relay_port); + + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(relay_hostname); + + let channel = Channel::from_shared(client_addr.to_string()) + .unwrap() + .tls_config(tls) + .expect(&format!( + "Error in TLS configuration for client: {}", + client_addr.to_string() + )) + .connect() + .await + .unwrap(); + + let client = SatpClient::new(channel); + send_driver_mock_send_asset_status_helper(client, request_id.to_string()); + } else { + let client_result = SatpClient::connect(client_addr).await; + match client_result { + Ok(client) => { + // Sends Mocked payload back. + send_driver_mock_send_asset_status_helper(client, request_id.to_string()); + } + Err(e) => { + // TODO: Add better error handling (Attempt a few times?) + panic!("Failed to connect to client. Error: {}", e.to_string()); + } + } + } + let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id, @@ -218,6 +309,11 @@ impl DriverCommunication for DriverCommunicationService { } } +pub fn get_relay_from_perform_lock(perform_lock_request: PerformLockRequest) -> String { + // TODO + return "Dummy_Relay".to_string(); +} + fn send_driver_mock_state_helper(client: DataTransferClient, request_id: String) { tokio::spawn(async move { let my_time = time::Duration::from_millis(3000); @@ -228,7 +324,7 @@ fn send_driver_mock_state_helper(client: DataTransferClient, request_id timestamp: "I am time".to_string(), proof_type: "I am proof".to_string(), serialization_format: "Proto".to_string(), - protocol: meta::Protocol::Fabric as i32 + protocol: meta::Protocol::Fabric as i32, }), data: "This is a mocked payload".as_bytes().to_vec(), })), @@ -239,7 +335,10 @@ fn send_driver_mock_state_helper(client: DataTransferClient, request_id println!("Ack from remote relay={:?}", response); }); } -fn send_driver_mock_subscription_state_helper(client: EventSubscribeClient, request_id: String) { +fn send_driver_mock_subscription_state_helper( + client: EventSubscribeClient, + request_id: String, +) { tokio::spawn(async move { let my_time = time::Duration::from_millis(3000); sleep(my_time); @@ -254,6 +353,30 @@ fn send_driver_mock_subscription_state_helper(client: EventSubscribeClient, request_id: String) { + tokio::spawn(async move { + let my_time = time::Duration::from_millis(3000); + sleep(my_time); + + let send_asset_status_request = SendAssetStatusRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + hash_prev_message: "hash_prev_message1".to_string(), + server_transfer_number: "server_transfer_number1".to_string(), + server_signature: "server_signature1".to_string(), + }; + println!("Sending send asset status request to remote gateway ..."); + let response = client + .clone() + .send_asset_status(send_asset_status_request) + .await; + println!("Ack from remote relay={:?}", response); + }); +} + #[tokio::main] async fn main() -> Result<(), Box> { // NOTE: This will need cleaning up @@ -290,7 +413,7 @@ async fn main() -> Result<(), Box> { .to_socket_addrs()? .next() .expect("Port number is potentially invalid. Unable to create SocketAddr"); - + let driver = DriverCommunicationService { config_lock: RwLock::new(settings.clone()), }; @@ -305,11 +428,11 @@ async fn main() -> Result<(), Box> { .tls_config(ServerTlsConfig::new().identity(identity))? .add_service(DriverCommunicationServer::new(driver)); server.serve(addr).await?; - } else { println!("DriverServer listening on {}", addr); // Spins up two gRPC services in a tonic server. One for relay to relay and one for network to relay communication. - let server = Server::builder().add_service(DriverCommunicationServer::new(driver)); + let server = + Server::builder().add_service(DriverCommunicationServer::new(driver)); server.serve(addr).await?; } } diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 51141e332a..fe1a56d25b 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -11,8 +11,9 @@ use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, - CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, - TransferCompletedRequest, TransferProposalClaimsRequest, TransferProposalReceiptRequest, + CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, SendAssetStatusRequest, + TransferCommenceRequest, TransferCompletedRequest, TransferProposalClaimsRequest, + TransferProposalReceiptRequest, }; use crate::db::Database; @@ -160,15 +161,9 @@ pub fn spawn_send_ack_commence_request( pub fn spawn_send_perform_lock_request( driver_info: Driver, ack_commence_request: AckCommenceRequest, - lock_assertion_request: LockAssertionRequest, - relay_host: String, - relay_port: String, - use_tls: bool, - tlsca_cert_path: String, - conf: Config, ) { tokio::spawn(async move { - let request_id = lock_assertion_request.session_id.to_string(); + let request_id = ack_commence_request.session_id.to_string(); println!( "Locking the asset of the lock assertion request id: {:?}", request_id @@ -185,22 +180,6 @@ pub fn spawn_send_perform_lock_request( // TODO: what to do in this case? } } - - // TODO: Subscribe to the status event - // Once the asset is locked, call the lock_assertion endpoint - let result = call_lock_assertion( - relay_host, - relay_port, - use_tls, - tlsca_cert_path.to_string(), - lock_assertion_request.clone(), - ) - .await; - - println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway - let request_id = lock_assertion_request.session_id.to_string(); - log_request_result_in_local_satp_db(&request_id, result, conf); }); } @@ -236,6 +215,33 @@ pub fn spawn_send_lock_assertion_broadcast_request( }); } +pub fn spawn_send_lock_assertion_request( + lock_assertion_request: LockAssertionRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = lock_assertion_request.session_id.to_string(); + println!("Sending the lock assertion request {:?}", request_id); + let result = call_lock_assertion( + relay_host, + relay_port, + use_tls, + tlsca_cert_path.to_string(), + lock_assertion_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = lock_assertion_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + // Sends a request to the receiving gateway pub fn spawn_send_commit_prepare_request( commit_prepare_request: CommitPrepareRequest, @@ -792,7 +798,7 @@ pub fn create_ack_commence_request( } pub fn create_lock_assertion_request( - ack_commence_request: AckCommenceRequest, + send_asset_status_request: SendAssetStatusRequest, ) -> LockAssertionRequest { // TODO: remove hard coded values let lock_assertion_request = LockAssertionRequest { @@ -890,7 +896,9 @@ pub fn create_transfer_completed_request( pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> PerformLockRequest { // TODO: remove hard coded values - let perform_lock_request = PerformLockRequest {}; + let perform_lock_request = PerformLockRequest { + session_id: "session_id1".to_string(), + }; return perform_lock_request; } @@ -1068,6 +1076,13 @@ pub fn get_relay_from_ack_final_receipt( return ("localhost".to_string(), "9085".to_string()); } +pub fn get_relay_from_send_asset_status( + send_asset_status_request: SendAssetStatusRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + pub fn get_driver_address_from_ack_commence(ack_commence_request: AckCommenceRequest) -> String { // TODO return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index f154cce560..0d95acab03 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -3,8 +3,9 @@ use weaverpb::common::ack::{ack, Ack}; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{ AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, - CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, - TransferCompletedRequest, TransferProposalClaimsRequest, TransferProposalReceiptRequest, + CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, SendAssetStatusRequest, + TransferCommenceRequest, TransferCompletedRequest, TransferProposalClaimsRequest, + TransferProposalReceiptRequest, }; // Internal modules @@ -26,13 +27,14 @@ use super::satp_helper::{ get_driver_address_from_ack_commence, get_relay_from_ack_commence, get_relay_from_ack_final_receipt, get_relay_from_commit_final_assertion, get_relay_from_commit_prepare, get_relay_from_commit_ready, get_relay_from_lock_assertion, - get_relay_from_lock_assertion_receipt, get_relay_from_transfer_commence, - get_relay_from_transfer_proposal_claims, get_relay_from_transfer_proposal_receipt, - get_relay_params, get_request_id_from_transfer_proposal_claims, - spawn_send_ack_commence_request, spawn_send_ack_final_receipt_broadcast_request, - spawn_send_assign_asset_request, spawn_send_commit_prepare_request, - spawn_send_create_asset_request, spawn_send_extinguish_request, - spawn_send_lock_assertion_broadcast_request, spawn_send_perform_lock_request, + get_relay_from_lock_assertion_receipt, get_relay_from_send_asset_status, + get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, + get_relay_from_transfer_proposal_receipt, get_relay_params, + get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, + spawn_send_ack_final_receipt_broadcast_request, spawn_send_assign_asset_request, + spawn_send_commit_prepare_request, spawn_send_create_asset_request, + spawn_send_extinguish_request, spawn_send_lock_assertion_broadcast_request, + spawn_send_lock_assertion_request, spawn_send_perform_lock_request, spawn_send_transfer_commence_request, spawn_send_transfer_proposal_receipt_request, }; use tokio::sync::RwLock; @@ -254,6 +256,57 @@ impl Satp for SatpService { } } + async fn send_asset_status( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got a send asset status request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let send_asset_status_request = request.into_inner().clone(); + let request_id = send_asset_status_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &send_asset_status_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored SendAssetStatusRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing SendAssetStatusRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_send_asset_status_request(send_asset_status_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of send asset status request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Send asset status failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + async fn lock_assertion( &self, request: Request, @@ -775,6 +828,41 @@ pub fn process_ack_commence_request( } } +pub fn process_send_asset_status_request( + send_asset_status_request: SendAssetStatusRequest, + conf: config::Config, +) -> Result { + let request_id = send_asset_status_request.session_id.to_string(); + let is_valid_request = is_valid_send_asset_status_request(send_asset_status_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The send asset status request is valid\n"); + match send_lock_assertion_request(send_asset_status_request, conf) { + Ok(ack) => { + println!("Ack send asset status request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: send asset status request failed. {:?}", e), + }); + } + } + } else { + println!("The send asset status request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The send asset status request is invalid".to_string(), + }); + } +} + pub fn process_lock_assertion_request( lock_assertion_request: LockAssertionRequest, conf: config::Config, @@ -1071,6 +1159,33 @@ fn send_ack_commence_request( return Ok(reply); } +fn send_lock_assertion_request( + send_asset_status_request: SendAssetStatusRequest, + conf: config::Config, +) -> Result { + let request_id = &send_asset_status_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_send_asset_status(send_asset_status_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let lock_assertion_request = create_lock_assertion_request(send_asset_status_request.clone()); + + spawn_send_lock_assertion_request( + lock_assertion_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Send Asset Status request".to_string(), + }; + return Ok(reply); +} + fn send_lock_assertion_receipt_request( lock_assertion_request: LockAssertionRequest, conf: config::Config, @@ -1103,25 +1218,12 @@ fn send_perform_lock_request( conf: config::Config, ) -> Result { let request_id = &ack_commence_request.session_id.to_string(); - let (relay_host, relay_port) = get_relay_from_ack_commence(ack_commence_request.clone()); - let (use_tls, tlsca_cert_path) = - get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let lock_assertion_request = create_lock_assertion_request(ack_commence_request.clone()); let driver_address = get_driver_address_from_ack_commence(ack_commence_request.clone()); let parsed_address = parse_address(driver_address)?; let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); match result { Ok(driver_info) => { - spawn_send_perform_lock_request( - driver_info, - ack_commence_request, - lock_assertion_request, - relay_host, - relay_port, - use_tls, - tlsca_cert_path, - conf, - ); + spawn_send_perform_lock_request(driver_info, ack_commence_request); let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), @@ -1142,33 +1244,6 @@ fn send_perform_lock_request( } } -fn send_lock_assertion_broadcast_request( - lock_assertion_request: LockAssertionRequest, - conf: config::Config, -) -> Result { - let request_id = &lock_assertion_request.session_id.to_string(); - let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); - let (use_tls, tlsca_cert_path) = - get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let lock_assertion_receipt_request = - create_lock_assertion_receipt_request(lock_assertion_request.clone()); - - spawn_send_lock_assertion_broadcast_request( - lock_assertion_receipt_request, - relay_host, - relay_port, - use_tls, - tlsca_cert_path, - conf, - ); - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request_id.to_string(), - message: "Ack of lock assert request".to_string(), - }; - return Ok(reply); -} - fn send_commit_prepare_request( lock_assertion_receipt_request: LockAssertionReceiptRequest, conf: config::Config, @@ -1378,3 +1453,8 @@ fn is_valid_transfer_completed_request( //TODO true } + +fn is_valid_send_asset_status_request(send_asset_status_request: SendAssetStatusRequest) -> bool { + //TODO + true +} From ee007ad2b59a27b6b6cefdc68be02b7e042dddfa Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 15 Aug 2023 11:24:37 +0100 Subject: [PATCH 20/59] Implemented the status check functionality required for 2.1B, 3.2B, 3.4B, and 3.6B --- .../protos-rs/pkg/src/generated/relay.satp.rs | 2 + weaver/common/protos/relay/satp.proto | 1 + weaver/core/relay/driver/driver.rs | 1 + weaver/core/relay/src/services/satp_helper.rs | 137 +++++++-- .../core/relay/src/services/satp_service.rs | 283 +++++++++++------- 5 files changed, 289 insertions(+), 135 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index c1b94e14b9..b7147bd954 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -124,6 +124,8 @@ pub struct SendAssetStatusRequest { pub server_transfer_number: ::prost::alloc::string::String, #[prost(string, tag = "8")] pub server_signature: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub status: ::prost::alloc::string::String, } #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos/relay/satp.proto b/weaver/common/protos/relay/satp.proto index d7dd1b63c4..3d20759879 100644 --- a/weaver/common/protos/relay/satp.proto +++ b/weaver/common/protos/relay/satp.proto @@ -116,6 +116,7 @@ message SendAssetStatusRequest { string hash_prev_message = 6; string server_transfer_number = 7; string server_signature = 8; + string status = 9; } message LockAssertionRequest { diff --git a/weaver/core/relay/driver/driver.rs b/weaver/core/relay/driver/driver.rs index 34b78f6ec5..446c98340d 100644 --- a/weaver/core/relay/driver/driver.rs +++ b/weaver/core/relay/driver/driver.rs @@ -367,6 +367,7 @@ fn send_driver_mock_send_asset_status_helper(client: SatpClient, reques hash_prev_message: "hash_prev_message1".to_string(), server_transfer_number: "server_transfer_number1".to_string(), server_signature: "server_signature1".to_string(), + status: "status1".to_string(), }; println!("Sending send asset status request to remote gateway ..."); let response = client diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index fe1a56d25b..9894ca8f69 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -160,17 +160,17 @@ pub fn spawn_send_ack_commence_request( pub fn spawn_send_perform_lock_request( driver_info: Driver, - ack_commence_request: AckCommenceRequest, + perform_lock_request: PerformLockRequest, ) { tokio::spawn(async move { - let request_id = ack_commence_request.session_id.to_string(); + let request_id = perform_lock_request.session_id.to_string(); println!( "Locking the asset of the lock assertion request id: {:?}", request_id ); // TODO: pass the required info to lock the relevant asset // Call the driver to lock the asset - let result = call_perform_lock(driver_info, ack_commence_request).await; + let result = call_perform_lock(driver_info, perform_lock_request).await; match result { Ok(_) => { println!("Perform lock request sent to driver\n") @@ -184,7 +184,7 @@ pub fn spawn_send_perform_lock_request( } pub fn spawn_send_lock_assertion_broadcast_request( - lock_assertion_receipt_request: LockAssertionReceiptRequest, + lock_assertion_request: LockAssertionRequest, relay_host: String, relay_port: String, use_tls: bool, @@ -192,13 +192,16 @@ pub fn spawn_send_lock_assertion_broadcast_request( conf: Config, ) { tokio::spawn(async move { - let request_id = lock_assertion_receipt_request.session_id.to_string(); + let request_id = lock_assertion_request.session_id.to_string(); println!("Broadcasting the lock assertion request {:?}", request_id); // TODO // Broadcast the message to the network // Subscribe to the status event // Once the message is broadcast, call the call_lock_assertion_receipt endpoint // log the results + + let lock_assertion_receipt_request = + create_lock_assertion_receipt_request(lock_assertion_request.clone()); let result = call_lock_assertion_receipt( relay_host, relay_port, @@ -258,10 +261,6 @@ pub fn spawn_send_commit_prepare_request( // Spawning new thread to make the call_commit_prepare to receiver gateway tokio::spawn(async move { let request_id = commit_prepare_request.session_id.to_string(); - println!( - "Sending commit prepare request to receiver gateway: Request ID = {:?}", - request_id - ); let result = call_commit_prepare( relay_host, relay_port, @@ -278,7 +277,7 @@ pub fn spawn_send_commit_prepare_request( } pub fn spawn_send_create_asset_request( - commit_ready_request: CommitReadyRequest, + commit_prepare_request: CommitPrepareRequest, relay_host: String, relay_port: String, use_tls: bool, @@ -286,9 +285,9 @@ pub fn spawn_send_create_asset_request( conf: Config, ) { tokio::spawn(async move { - let request_id = commit_ready_request.session_id.to_string(); + let request_id = commit_prepare_request.session_id.to_string(); println!( - "Creating the asset corresponding to the commit ready request {:?}", + "Creating the asset corresponding to the commit prepare request {:?}", request_id ); // TODO @@ -296,6 +295,19 @@ pub fn spawn_send_create_asset_request( // Subscribe to the status event // Once the message is broadcast, call the call_commit_ready endpoint // log the results + }); +} + +pub fn spawn_send_commit_ready_request( + commit_ready_request: CommitReadyRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = commit_ready_request.session_id.to_string(); let result = call_commit_ready( relay_host, relay_port, @@ -313,7 +325,7 @@ pub fn spawn_send_create_asset_request( } pub fn spawn_send_assign_asset_request( - ack_final_receipt_request: AckFinalReceiptRequest, + commit_final_assertion_request: CommitFinalAssertionRequest, relay_host: String, relay_port: String, use_tls: bool, @@ -321,15 +333,28 @@ pub fn spawn_send_assign_asset_request( conf: Config, ) { tokio::spawn(async move { - let request_id = ack_final_receipt_request.session_id.to_string(); + let request_id = commit_final_assertion_request.session_id.to_string(); println!( - "Assigning the asset corresponding to the commit final assertion request {:?}", + "Assigning the asset corresponding to the commit final assertion request {:?}", request_id ); // TODO // Assigning the asset in the target network // Once the asset is assigned, call the call_ack_final_receipt endpoint // log the results + }); +} + +pub fn spawn_send_ack_final_receipt_request( + ack_final_receipt_request: AckFinalReceiptRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = ack_final_receipt_request.session_id.to_string(); let result = call_ack_final_receipt( relay_host, relay_port, @@ -347,7 +372,7 @@ pub fn spawn_send_assign_asset_request( } pub fn spawn_send_ack_final_receipt_broadcast_request( - transfer_completed_request: TransferCompletedRequest, + ack_final_receipt_request: AckFinalReceiptRequest, relay_host: String, relay_port: String, use_tls: bool, @@ -355,15 +380,18 @@ pub fn spawn_send_ack_final_receipt_broadcast_request( conf: Config, ) { tokio::spawn(async move { - let request_id = transfer_completed_request.session_id.to_string(); + let request_id = ack_final_receipt_request.session_id.to_string(); println!( - "Acknowledge final receipt broadcast of the transfer completed request {:?}", + "Acknowledge final receipt broadcast of the ack final receipt request {:?}", request_id ); // TODO // Ack final receipt broadcast // Once the broadcast is done, call the call_transfer_completed endpoint // log the results + + let transfer_completed_request = + create_transfer_completed_request(ack_final_receipt_request); let result = call_transfer_completed( relay_host, relay_port, @@ -381,7 +409,7 @@ pub fn spawn_send_ack_final_receipt_broadcast_request( } pub fn spawn_send_extinguish_request( - commit_final_assertion_request: CommitFinalAssertionRequest, + commit_ready_request: CommitReadyRequest, relay_host: String, relay_port: String, use_tls: bool, @@ -389,7 +417,7 @@ pub fn spawn_send_extinguish_request( conf: Config, ) { tokio::spawn(async move { - let request_id = commit_final_assertion_request.session_id.to_string(); + let request_id = commit_ready_request.session_id.to_string(); println!( "Extinguishing the asset corresponding to the commit final assertion request {:?}", request_id @@ -398,6 +426,23 @@ pub fn spawn_send_extinguish_request( // Assigning the asset in the target network // Once the asset is assigned, call the call_ack_final_receipt endpoint // log the results + }); +} + +pub fn spawn_send_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = commit_final_assertion_request.session_id.to_string(); + println!( + "Extinguishing the asset corresponding to the commit final assertion request {:?}", + request_id + ); let result = call_commit_final_assertion_receipt( relay_host, relay_port, @@ -416,11 +461,10 @@ pub fn spawn_send_extinguish_request( async fn call_perform_lock( driver_info: Driver, - ack_commence_request: AckCommenceRequest, + perform_lock_request: PerformLockRequest, ) -> Result<(), Error> { let client = get_driver_client(driver_info).await?; println!("Sending request to driver to lock the asset"); - let perform_lock_request = create_perform_lock_request(ack_commence_request); let ack = client .clone() .perform_lock(perform_lock_request) @@ -558,7 +602,7 @@ pub async fn call_lock_assertion_receipt( Ok(response) } -// Call the call_commit_ready endpoint on the sending gateway +// Call the call_commit_prepare endpoint on the sending gateway pub async fn call_commit_prepare( relay_host: String, relay_port: String, @@ -847,7 +891,7 @@ pub fn create_commit_prepare_request( } pub fn create_commit_ready_request( - commit_prepare_request: CommitPrepareRequest, + send_asset_status_request: SendAssetStatusRequest, ) -> CommitReadyRequest { // TODO: remove hard coded values let commit_ready_request = CommitReadyRequest { @@ -859,7 +903,7 @@ pub fn create_commit_ready_request( } pub fn create_commit_final_assertion_request( - commit_ready_request: CommitReadyRequest, + send_asset_status_request: SendAssetStatusRequest, ) -> CommitFinalAssertionRequest { // TODO: remove hard coded values let commit_final_assertion_request = CommitFinalAssertionRequest { @@ -871,7 +915,7 @@ pub fn create_commit_final_assertion_request( } pub fn create_ack_final_receipt_request( - commit_final_assertion_request: CommitFinalAssertionRequest, + send_asset_status_request: SendAssetStatusRequest, ) -> AckFinalReceiptRequest { // TODO: remove hard coded values let ack_final_receipt_request = AckFinalReceiptRequest { @@ -902,6 +946,45 @@ pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> return perform_lock_request; } +pub fn generate_commit_final_assertion_request( + commit_ready_request: CommitReadyRequest, +) -> CommitFinalAssertionRequest { + // TODO Get the corresponding send_asset_status_request from db + // TODO: remove hard coded values + let commit_final_assertion_request = CommitFinalAssertionRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_final_assertion_request; +} + +pub fn generate_commit_ready_request( + commit_prepare_request: CommitPrepareRequest, +) -> CommitReadyRequest { + // TODO Get the corresponding send_asset_status_request from db + // TODO: remove hard coded values + let commit_ready_request = CommitReadyRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_ready_request; +} + +pub fn generate_ack_final_receipt_request( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> AckFinalReceiptRequest { + // TODO Get the corresponding send_asset_status_request from db + // TODO: remove hard coded values + let ack_final_receipt_request = AckFinalReceiptRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return ack_final_receipt_request; +} + pub fn get_satp_requests_local_db(conf: Config) -> Database { let db = Database { db_path: format!( @@ -1083,7 +1166,7 @@ pub fn get_relay_from_send_asset_status( return ("localhost".to_string(), "9085".to_string()); } -pub fn get_driver_address_from_ack_commence(ack_commence_request: AckCommenceRequest) -> String { +pub fn get_driver_address_from_perform_lock(perform_lock_request: PerformLockRequest) -> String { // TODO return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); } diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 0d95acab03..b9bf229eb9 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,5 +1,6 @@ // Internal generated modules use weaverpb::common::ack::{ack, Ack}; +use weaverpb::driver::driver::PerformLockRequest; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{ AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, @@ -12,8 +13,9 @@ use weaverpb::relay::satp::{ use crate::error::Error; use crate::relay_proto::parse_address; use crate::services::satp_helper::{ - create_ack_error_message, get_request_id_from_transfer_proposal_receipt, - log_request_in_local_satp_db, log_request_in_remote_satp_db, + create_ack_error_message, create_perform_lock_request, + get_request_id_from_transfer_proposal_receipt, log_request_in_local_satp_db, + log_request_in_remote_satp_db, }; use super::helpers::get_driver; @@ -21,21 +23,20 @@ use super::helpers::get_driver; use super::satp_helper::{ create_ack_commence_request, create_ack_final_receipt_request, create_commit_final_assertion_request, create_commit_prepare_request, - create_commit_ready_request, create_lock_assertion_receipt_request, - create_lock_assertion_request, create_transfer_commence_request, + create_commit_ready_request, create_lock_assertion_request, create_transfer_commence_request, create_transfer_completed_request, create_transfer_proposal_receipt_request, - get_driver_address_from_ack_commence, get_relay_from_ack_commence, + get_driver_address_from_perform_lock, get_relay_from_ack_commence, get_relay_from_ack_final_receipt, get_relay_from_commit_final_assertion, get_relay_from_commit_prepare, get_relay_from_commit_ready, get_relay_from_lock_assertion, - get_relay_from_lock_assertion_receipt, get_relay_from_send_asset_status, - get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, - get_relay_from_transfer_proposal_receipt, get_relay_params, + get_relay_from_transfer_commence, get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, - spawn_send_ack_final_receipt_broadcast_request, spawn_send_assign_asset_request, - spawn_send_commit_prepare_request, spawn_send_create_asset_request, - spawn_send_extinguish_request, spawn_send_lock_assertion_broadcast_request, - spawn_send_lock_assertion_request, spawn_send_perform_lock_request, - spawn_send_transfer_commence_request, spawn_send_transfer_proposal_receipt_request, + spawn_send_ack_final_receipt_broadcast_request, spawn_send_ack_final_receipt_request, + spawn_send_assign_asset_request, spawn_send_commit_final_assertion_request, + spawn_send_commit_prepare_request, spawn_send_commit_ready_request, + spawn_send_create_asset_request, spawn_send_extinguish_request, + spawn_send_lock_assertion_broadcast_request, spawn_send_lock_assertion_request, + spawn_send_perform_lock_request, spawn_send_transfer_commence_request, + spawn_send_transfer_proposal_receipt_request, }; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; @@ -657,7 +658,9 @@ pub fn process_transfer_proposal_claims_request( if is_valid_request { println!("The transfer proposal claims request is valid\n"); - match send_transfer_proposal_receipt_request(transfer_proposal_claims_request, conf) { + let transfer_proposal_receipt_request = + create_transfer_proposal_receipt_request(transfer_proposal_claims_request.clone()); + match send_transfer_proposal_receipt_request(transfer_proposal_receipt_request, conf) { Ok(ack) => { println!("Ack transfer proposal claims request."); let reply = Ok(ack); @@ -693,7 +696,9 @@ pub fn process_transfer_proposal_receipt_request( if is_valid_request { println!("The transfer proposal receipt request is valid\n"); - match send_transfer_commence_request(transfer_proposal_receipt_request, conf) { + let transfer_commence_request = + create_transfer_commence_request(transfer_proposal_receipt_request.clone()); + match send_transfer_commence_request(transfer_commence_request, conf) { Ok(ack) => { println!("Ack transfer proposal receipt request."); let reply = Ok(ack); @@ -729,7 +734,8 @@ pub fn process_transfer_commence_request( if is_valid_request { println!("The transfer commence request is valid\n"); - match send_ack_commence_request(transfer_commence_request, conf) { + let ack_commence_request = create_ack_commence_request(transfer_commence_request.clone()); + match send_ack_commence_request(ack_commence_request, conf) { Ok(ack) => { println!("Ack transfer commence request."); let reply = Ok(ack); @@ -754,43 +760,6 @@ pub fn process_transfer_commence_request( } } -pub fn process_tranfer_proposal_receipt_request( - transfer_proposal_receipt_request: TransferProposalReceiptRequest, - conf: config::Config, -) -> Result { - let request_id = - get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); - let is_valid_request = - is_valid_transfer_proposal_receipt_request(transfer_proposal_receipt_request.clone()); - - // TODO some processing - if is_valid_request { - println!("The transfer proposal receipt request is valid\n"); - match send_transfer_commence_request(transfer_proposal_receipt_request, conf) { - Ok(ack) => { - println!("Ack transfer proposal receipt request."); - let reply = Ok(ack); - println!("Sending back Ack: {:?}\n", reply); - reply - } - Err(e) => { - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error: Ack transfer proposal receipt failed. {:?}", e), - }); - } - } - } else { - println!("The transfer proposal receipt request is invalid\n"); - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: "Error: The transfer proposal receipt request is invalid".to_string(), - }); - } -} - /// process_ack_commence_request is invoked by the receiver gateway to ack the transfer commence request /// requested ed by the sender gateway pub fn process_ack_commence_request( @@ -803,7 +772,8 @@ pub fn process_ack_commence_request( // TODO some processing if is_valid_request { println!("The ack commence request is valid\n"); - match send_perform_lock_request(ack_commence_request, conf) { + let perform_lock_request = create_perform_lock_request(ack_commence_request); + match send_perform_lock_request(perform_lock_request, conf) { Ok(ack) => { println!("Ack ack commence request."); let reply = Ok(ack); @@ -838,9 +808,40 @@ pub fn process_send_asset_status_request( // TODO some processing if is_valid_request { println!("The send asset status request is valid\n"); - match send_lock_assertion_request(send_asset_status_request, conf) { + + let result; + let status = send_asset_status_request.status.as_str(); + match status { + "Locked" => { + println!("Received asset status as Locked. Sending the lock assertion request"); + let lock_assertion_request = + create_lock_assertion_request(send_asset_status_request); + result = send_lock_assertion_request(lock_assertion_request, conf) + } + "Created" => { + println!("Received asset status as Created. Sending the commit ready request"); + let commit_ready_request = create_commit_ready_request(send_asset_status_request); + result = send_commit_ready_request(commit_ready_request, conf); + } + "Extinguished" => { + println!("Received asset status as Extinguished. Sending the commit final assertion request"); + let commit_final_assertion_request = + create_commit_final_assertion_request(send_asset_status_request); + result = send_commit_final_assertion_request(commit_final_assertion_request, conf) + } + "Finalized" => { + println!( + "Received asset status as Finalized. Sending the ack final receipt request" + ); + let ack_final_receipt_request = + create_ack_final_receipt_request(send_asset_status_request.clone()); + result = send_ack_final_receipt_request(ack_final_receipt_request, conf) + } + _ => result = Err(Error::Simple(format!("Invalid asset status: {}", status))), + } + + match result { Ok(ack) => { - println!("Ack send asset status request."); let reply = Ok(ack); println!("Sending back Ack: {:?}\n", reply); reply @@ -849,7 +850,7 @@ pub fn process_send_asset_status_request( return Ok(Ack { status: ack::Status::Error as i32, request_id: request_id.to_string(), - message: format!("Error: send asset status request failed. {:?}", e), + message: format!("Error: sending request failed. {:?}", e), }); } } @@ -872,7 +873,7 @@ pub fn process_lock_assertion_request( if is_valid_request { println!("The lock assertion request is valid\n"); - match send_lock_assertion_receipt_request(lock_assertion_request, conf) { + match send_lock_assertion_broadcast_request(lock_assertion_request, conf) { Ok(ack) => { println!("Ack lock assertion request."); let reply = Ok(ack); @@ -908,7 +909,9 @@ pub fn process_lock_assertion_receipt_request( // TODO some processing if is_valid_request { println!("The lock assertion receipt request is valid\n"); - match send_commit_prepare_request(lock_assertion_receipt_request, conf) { + let commit_prepare_request = + create_commit_prepare_request(lock_assertion_receipt_request.clone()); + match send_commit_prepare_request(commit_prepare_request, conf) { Ok(ack) => { println!("Ack lock assertion receipt request."); let reply = Ok(ack); @@ -943,7 +946,7 @@ pub fn process_commit_prepare_request( // TODO some processing if is_valid_request { println!("The commit prepare request is valid\n"); - match send_commit_ready_request(commit_prepare_request, conf) { + match send_create_asset_request(commit_prepare_request, conf) { Ok(ack) => { println!("Ack commit prepare request."); let reply = Ok(ack); @@ -978,7 +981,7 @@ pub fn process_commit_ready_request( // TODO some processing if is_valid_request { println!("The commit ready request is valid\n"); - match send_commit_final_assertion_request(commit_ready_request, conf) { + match send_extinguish_request(commit_ready_request, conf) { Ok(ack) => { println!("Ack commit ready request."); let reply = Ok(ack); @@ -1014,7 +1017,7 @@ pub fn process_commit_final_assertion_request( // TODO some processing if is_valid_request { println!("The commit final assertion request is valid\n"); - match send_ack_final_receipt_request(commit_final_assertion_request, conf) { + match send_assign_asset_request(commit_final_assertion_request, conf) { Ok(ack) => { println!("Ack commit final assertion request."); let reply = Ok(ack); @@ -1049,7 +1052,7 @@ pub fn process_ack_final_receipt_request( // TODO some processing if is_valid_request { println!("The ack final receipt request is valid\n"); - match send_transfer_completed_request(ack_final_receipt_request, conf) { + match send_ack_final_receipt_broadcast_request(ack_final_receipt_request, conf) { Ok(ack) => { println!("Ack ack final receipt request."); let reply = Ok(ack); @@ -1075,17 +1078,15 @@ pub fn process_ack_final_receipt_request( } fn send_transfer_proposal_receipt_request( - transfer_proposal_claims_request: TransferProposalClaimsRequest, + transfer_proposal_receipt_request: TransferProposalReceiptRequest, conf: config::Config, ) -> Result { let request_id = - get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); + get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); let (relay_host, relay_port) = - get_relay_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); + get_relay_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let transfer_proposal_receipt_request = - create_transfer_proposal_receipt_request(transfer_proposal_claims_request.clone()); spawn_send_transfer_proposal_receipt_request( transfer_proposal_receipt_request, @@ -1104,17 +1105,14 @@ fn send_transfer_proposal_receipt_request( } fn send_transfer_commence_request( - transfer_proposal_receipt_request: TransferProposalReceiptRequest, + transfer_commence_request: TransferCommenceRequest, conf: config::Config, ) -> Result { - let request_id = - get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); + let request_id = transfer_commence_request.session_id.clone(); let (relay_host, relay_port) = - get_relay_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); + get_relay_from_transfer_commence(transfer_commence_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let transfer_commence_request = - create_transfer_commence_request(transfer_proposal_receipt_request.clone()); spawn_send_transfer_commence_request( transfer_commence_request, @@ -1133,15 +1131,13 @@ fn send_transfer_commence_request( } fn send_ack_commence_request( - transfer_commence_request: TransferCommenceRequest, + ack_commence_request: AckCommenceRequest, conf: config::Config, ) -> Result { - let request_id = &transfer_commence_request.session_id.to_string(); - let (relay_host, relay_port) = - get_relay_from_transfer_commence(transfer_commence_request.clone()); + let request_id = &ack_commence_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_ack_commence(ack_commence_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let ack_commence_request = create_ack_commence_request(transfer_commence_request.clone()); spawn_send_ack_commence_request( ack_commence_request, @@ -1160,15 +1156,13 @@ fn send_ack_commence_request( } fn send_lock_assertion_request( - send_asset_status_request: SendAssetStatusRequest, + lock_assertion_request: LockAssertionRequest, conf: config::Config, ) -> Result { - let request_id = &send_asset_status_request.session_id.to_string(); - let (relay_host, relay_port) = - get_relay_from_send_asset_status(send_asset_status_request.clone()); + let request_id = &lock_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let lock_assertion_request = create_lock_assertion_request(send_asset_status_request.clone()); spawn_send_lock_assertion_request( lock_assertion_request, @@ -1186,7 +1180,7 @@ fn send_lock_assertion_request( return Ok(reply); } -fn send_lock_assertion_receipt_request( +fn send_lock_assertion_broadcast_request( lock_assertion_request: LockAssertionRequest, conf: config::Config, ) -> Result { @@ -1194,11 +1188,9 @@ fn send_lock_assertion_receipt_request( let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let lock_assertion_receipt_request = - create_lock_assertion_receipt_request(lock_assertion_request.clone()); spawn_send_lock_assertion_broadcast_request( - lock_assertion_receipt_request, + lock_assertion_request, relay_host, relay_port, use_tls, @@ -1214,16 +1206,16 @@ fn send_lock_assertion_receipt_request( } fn send_perform_lock_request( - ack_commence_request: AckCommenceRequest, + perform_lock_request: PerformLockRequest, conf: config::Config, ) -> Result { - let request_id = &ack_commence_request.session_id.to_string(); - let driver_address = get_driver_address_from_ack_commence(ack_commence_request.clone()); + let request_id = &perform_lock_request.session_id.to_string(); + let driver_address = get_driver_address_from_perform_lock(perform_lock_request.clone()); let parsed_address = parse_address(driver_address)?; let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); match result { Ok(driver_info) => { - spawn_send_perform_lock_request(driver_info, ack_commence_request); + spawn_send_perform_lock_request(driver_info, perform_lock_request); let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), @@ -1245,16 +1237,13 @@ fn send_perform_lock_request( } fn send_commit_prepare_request( - lock_assertion_receipt_request: LockAssertionReceiptRequest, + commit_prepare_request: CommitPrepareRequest, conf: config::Config, ) -> Result { - let request_id = &lock_assertion_receipt_request.session_id.to_string(); - let (relay_host, relay_port) = - get_relay_from_lock_assertion_receipt(lock_assertion_receipt_request.clone()); + let request_id = &commit_prepare_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let commit_prepare_request = - create_commit_prepare_request(lock_assertion_receipt_request.clone()); spawn_send_commit_prepare_request( commit_prepare_request, @@ -1273,6 +1262,33 @@ fn send_commit_prepare_request( } fn send_commit_ready_request( + commit_ready_request: CommitReadyRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_ready_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_commit_ready(commit_ready_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_commit_ready_request( + commit_ready_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_create_asset_request( commit_prepare_request: CommitPrepareRequest, conf: config::Config, ) -> Result { @@ -1281,10 +1297,9 @@ fn send_commit_ready_request( let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let commit_ready_request = create_commit_ready_request(commit_prepare_request.clone()); spawn_send_create_asset_request( - commit_ready_request, + commit_prepare_request, relay_host, relay_port, use_tls, @@ -1300,7 +1315,7 @@ fn send_commit_ready_request( return Ok(reply); } -fn send_commit_final_assertion_request( +fn send_extinguish_request( commit_ready_request: CommitReadyRequest, conf: config::Config, ) -> Result { @@ -1309,10 +1324,36 @@ fn send_commit_final_assertion_request( let (relay_host, relay_port) = get_relay_from_commit_ready(commit_ready_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let commit_final_assertion_request = - create_commit_final_assertion_request(commit_ready_request.clone()); spawn_send_extinguish_request( + commit_ready_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_final_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_commit_final_assertion(commit_final_assertion_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_commit_final_assertion_request( commit_final_assertion_request, relay_host, relay_port, @@ -1330,6 +1371,34 @@ fn send_commit_final_assertion_request( } fn send_ack_final_receipt_request( + ack_final_receipt_request: AckFinalReceiptRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &ack_final_receipt_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_ack_final_receipt_request( + ack_final_receipt_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_assign_asset_request( commit_final_assertion_request: CommitFinalAssertionRequest, conf: config::Config, ) -> Result { @@ -1339,11 +1408,9 @@ fn send_ack_final_receipt_request( get_relay_from_commit_final_assertion(commit_final_assertion_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let ack_final_receipt_request = - create_ack_final_receipt_request(commit_final_assertion_request.clone()); spawn_send_assign_asset_request( - ack_final_receipt_request, + commit_final_assertion_request, relay_host, relay_port, use_tls, @@ -1359,7 +1426,7 @@ fn send_ack_final_receipt_request( return Ok(reply); } -fn send_transfer_completed_request( +fn send_ack_final_receipt_broadcast_request( ack_final_receipt_request: AckFinalReceiptRequest, conf: config::Config, ) -> Result { @@ -1373,7 +1440,7 @@ fn send_transfer_completed_request( create_transfer_completed_request(ack_final_receipt_request.clone()); spawn_send_ack_final_receipt_broadcast_request( - transfer_completed_request, + ack_final_receipt_request, relay_host, relay_port, use_tls, From d3afbe2da95cb7637415c6c351595aca829c3057 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 21 Aug 2023 14:38:34 +0100 Subject: [PATCH 21/59] First iteration of switching to real driver (fabric) --- .../server/helpers/fabric-functions.ts | 714 ++++++++++++++++ .../fabric-driver/server/helpers/helpers.ts | 764 ++++++++++++++++++ .../interop-setup/configure-network.ts | 230 ++++++ .../fabric-driver/server/helpers/logger.ts | 29 + .../core/drivers/fabric-driver/server/satp.ts | 196 +++++ .../drivers/fabric-driver/server/server.ts | 22 + weaver/core/relay/config/Dummy_Relay.toml | 2 +- 7 files changed, 1956 insertions(+), 1 deletion(-) create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/helpers.ts create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/logger.ts create mode 100644 weaver/core/drivers/fabric-driver/server/satp.ts diff --git a/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts b/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts new file mode 100644 index 0000000000..08b7597980 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts @@ -0,0 +1,714 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Gateway, Wallets, Contract, X509Identity } from 'fabric-network' +import { getNetworkConfig, saveUserCertToFile, handlePromise } from './helpers' +import FabricCAServices from 'fabric-ca-client' +import { Certificate } from '@fidm/x509' +import { Utils, ICryptoKey } from 'fabric-common' +import * as membership_pb from "@hyperledger/cacti-weaver-protos-js/common/membership_pb" +import * as iin_agent_pb from "@hyperledger/cacti-weaver-protos-js/identity/agent_pb" +import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric' +import * as path from 'path' +import * as dotenv from 'dotenv' +dotenv.config({ path: path.resolve(__dirname, '../../.env') }) +import * as fs from 'fs' + +export type InvocationSpec = { + contractName: string + channel: string + args: string[] + ccFunc: string +} + +const getUserCertBase64 = async ( + networkName: string, + username: string +) => { + const wallet = await getWalletForNetwork(networkName) + const userId = await wallet.get(username) + if (!userId) { + throw new Error(`User ${username} not present in wallet of ${networkName}.`) + } + return Buffer.from((userId as X509Identity).credentials.certificate).toString('base64') +} + +const walletSetup = async ( + networkName: string, + ccp: any, + mspId: string, + userName: string, + userPwd: string = '', + isNetworkAdmin: boolean = false, + isIINAgent: boolean = false, + register: boolean = false, + logger: any = console +) => { + // Create a new CA client for interacting with the CA. + const org = ccp.client['organization'] + const caName = ccp.organizations[org]['certificateAuthorities'][0] + const caURL = ccp.certificateAuthorities[caName].url + const ca = new FabricCAServices(caURL) + const ident = ca.newIdentityService() + + const wallet = await getWalletForNetwork(networkName) + + // build a user object for authenticating with the CA + // Check to see if we've already enrolled the admin user. + let adminIdentity = await wallet.get('admin') + + if (adminIdentity) { + logger.debug( + 'An identity for the admin user "admin" already exists in the wallet.' + ) + } else { + // Enroll the admin user, and import the new identity into the wallet. + const enrollment = await ca.enroll({ + enrollmentID: 'admin', + enrollmentSecret: 'adminpw' + }) + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes() + }, + mspId: mspId, + type: 'X.509' + } + await wallet.put('admin', x509Identity) + adminIdentity = await wallet.get('admin') + } + const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type) + const adminUser = await provider.getUserContext(adminIdentity, 'admin') + const identity = await wallet.get(userName) + logger.debug(`user ${userName}`) + if (!identity) { + // Register the user, enroll the user, and import the new identity into the wallet. + if (!register) { + logger.error(`Identity ${userName} does not exist. Please add user in the network.\n`) + return + } + var secret, enrollment + var enrollmentDone = false + var attributes = [] + if (isNetworkAdmin) { + attributes.push({ "name": "network-admin", "value": "true", "ecert": true }) + } + if (isIINAgent) { + attributes.push({ "name": "iin-agent", "value": "true", "ecert": true }) + } + try { + if (!userPwd) { + secret = await ca.register( + { + affiliation: 'org1.department1', + enrollmentID: userName, + maxEnrollments: -1, + role: 'client', + attrs: attributes + }, + adminUser + ) + } + else { + secret = await ca.register( + { + affiliation: 'org1.department1', + enrollmentID: userName, + enrollmentSecret: userPwd, + maxEnrollments: -1, + role: 'client', + attrs: attributes + }, + adminUser + ) + } + logger.info(`Wallet Setup: Sucessful ${secret}`) + } catch(error) { + const registeredUser = `Identity '${userName}' is already ` + if (!userPwd || !(error.message.includes("Identity ") && error.message.includes(userName) && error.message.includes(" is already registered"))) { + throw new Error(`user ${userName} registration with Fabric CA failed with error: ${error}`) + } else { + try { + enrollment = await ca.enroll({ + enrollmentID: userName, + enrollmentSecret: userPwd + }) + enrollmentDone = true + } catch (error) { + throw new Error(`user ${userName} registration/enrollment with Fabric CA failed with error: ${error}`) + } + } + } + + if (!enrollmentDone) { + enrollment = await ca.enroll({ + enrollmentID: userName, + enrollmentSecret: secret + }) + } + + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes() + }, + mspId: mspId, + type: 'X.509' + } + await wallet.put(userName, x509Identity) + } + else { + logger.debug(`Identity ${userName} already exists.\n`) + } + + return wallet +} + +const enrollAndRecordWalletIdentity = async ( + userName: string, + userPwd: string, + networkName: string, + isNetworkAdmin: boolean = false, + isIINAgent: boolean = false, + logger: any = console +) => { + const net = getNetworkConfig(networkName) + const ccpPath = path.resolve(__dirname, net.connProfilePath) + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) + logger.info(net) + + const wallet = await walletSetup(networkName, ccp, net.mspId, userName, userPwd, isNetworkAdmin, isIINAgent, true) + saveUserCertToFile(userName, networkName) + + return wallet +} + +const getCurrentNetworkCredentialPath = (networkName: string): string => { + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, networkName) + : path.join(__dirname, '../data', 'credentials', networkName) + return credentialsPath +} + +const getCredentialPath = (): string => { + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER) + : path.join(__dirname, '../data', 'credentials') + return credentialsPath +} + +const generateAccessControl = async ( + channel: string, + contractName: string, + connProfilePath: string, + networkName: string, + templatePath: string, + username: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console +): Promise => { + const { wallet } = await fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + logger, + mspId + }) + const templateJSON = JSON.parse( + Buffer.from(fs.readFileSync(templatePath)).toString() + ) + const [keyCert, keyCertError] = await handlePromise( + getKeyAndCertForRemoteRequestbyUserName(wallet, username) + ) + if (keyCertError) { + logger.error( + 'Error fetching key and certificate from network', + keyCertError + ) + } + const updatedRules = templateJSON.rules.map(rule => { + if (rule.principalType == 'ca') { + rule.principal = mspId + } else if (rule.principalType == 'certificate') { + rule.principal = keyCert.cert + } else { + logger.error( + 'Error Invalid Principal Type in template file' + ) + } + return rule + }) + const accessControlJSON = { + ...templateJSON, + securityDomain: networkName, + rules: updatedRules + } + logger.debug(`AccessControlJSON ${JSON.stringify(accessControlJSON)}`) + const credentialsPath = getCurrentNetworkCredentialPath(networkName) + fs.writeFileSync( + path.join(credentialsPath, `access-control.json`), + JSON.stringify(accessControlJSON) + ) +} + +const generateVerificationPolicy = async ( + channel, + contractName, + connProfilePath, + networkName: string, + templatePath: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console +): Promise => { + const templateJSON = JSON.parse( + Buffer.from(fs.readFileSync(templatePath)).toString() + ) + const { gateway } = await fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + mspId, + logger + }) + + const network = await gateway.getNetwork(channel) + const mspConfig = await getMspConfig(network, logger) + const criteria = Object.keys(formatMSP(mspConfig, networkName).members) + const newIdentifiers = templateJSON.identifiers.map(identifier => { + identifier.policy.criteria = criteria + return identifier + }) + const verificationPolicy = { + ...templateJSON, + identifiers: newIdentifiers, + securityDomain: networkName + } + logger.debug(`VerificationPolicyJSON ${JSON.stringify(verificationPolicy)}`) + const credentialsPath = getCurrentNetworkCredentialPath(networkName) + logger.debug('Credential Path', credentialsPath) + fs.writeFileSync( + path.join(credentialsPath, `verification-policy.json`), + JSON.stringify(verificationPolicy) + ) +} + +const generateMembership = async ( + channel: string, + contractName: string, + connProfilePath: string, + networkName: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console, + iinAgent: boolean = false +): Promise => { + const { gateway } = await fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + mspId, + logger + }) + + const network = await gateway.getNetwork(channel) + const mspConfig = await getMspConfig(network, logger) + const membershipJSON = formatMSP(mspConfig, networkName) + const membershipJSONStr = JSON.stringify(membershipJSON) + logger.debug(`membershipJSON: ${membershipJSONStr}`) + + const credentialsPath = getCurrentNetworkCredentialPath(networkName) + logger.debug(`Credentials Path: ${credentialsPath}`) + if (!fs.existsSync(credentialsPath)) { + logger.debug(`Creating directory`) + fs.mkdirSync(credentialsPath, { recursive: true }) + } + + fs.writeFileSync( + path.join(credentialsPath, `membership.json`), + membershipJSONStr + ) + + if (iinAgent) { + // Generate protobufs and attestations for all other networks that have IIN Agents + const credentialFolderPath = getCredentialPath() + const otherNetworkNames = fs + .readdirSync(credentialFolderPath, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .filter(item => item.name.startsWith('network')) // HACK until we add IIN Agents for Corda networks + .map(item => item.name) + // Reorder the array so that the local network is the first element + // We need to record local membership before recording other networks' memberships + otherNetworkNames.splice(otherNetworkNames.indexOf(networkName), 1) + + if (otherNetworkNames.length > 0) { + // Convert membership object to protobuf + let membershipProto = new membership_pb.Membership() + membershipProto.setSecuritydomain(membershipJSON.securityDomain) + Object.keys(membershipJSON.members).forEach( (memberName, index) => { + const certInfo = membershipJSON.members[memberName] + let memberProto = new membership_pb.Member() + memberProto.setType(certInfo.type) + memberProto.setValue(certInfo.value) + membershipProto.getMembersMap().set(memberName, memberProto) + }) + + // For every other network, generate a counter attested membership set + const serializedMembership = membershipProto.serializeBinary() + const serializedMembershipBase64 = Buffer.from(serializedMembership).toString('base64') + const nonce = 'j849j94j40f440fkfjkld0e043' // Some random string + const membershipBase64WithNonce = serializedMembershipBase64 + nonce + // Get wallet key and cert for this network's IIN Agent + const localWallet = await getWalletForNetwork(networkName) + const localKeyCert = await getKeyAndCertForRemoteRequestbyUserName(localWallet, 'iinagent') + // Sign using wallet identity + let securityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() + securityDomainMember.setSecurityDomain(membershipJSON.securityDomain) + securityDomainMember.setMemberId(Object.keys(membershipJSON.members)[0]) + let localAttestation = new iin_agent_pb.Attestation() + localAttestation.setUnitIdentity(securityDomainMember) + localAttestation.setCertificate(localKeyCert.cert) + const localSig = InteroperableHelper.signMessage(membershipBase64WithNonce, localKeyCert.key.toBytes()) + localAttestation.setSignature(localSig) + localAttestation.setNonce(nonce) + let attestedMembershipSet = new iin_agent_pb.CounterAttestedMembership.AttestedMembershipSet() + attestedMembershipSet.setMembership(serializedMembershipBase64) + attestedMembershipSet.setAttestationsList( [ localAttestation ] ) + const serializedAttestedMembershipSet = attestedMembershipSet.serializeBinary() + const serializedttestedMembershipSetBase64 = Buffer.from(serializedAttestedMembershipSet).toString('base64') + const serializedttestedMembershipSetBase64WithNonce = serializedttestedMembershipSetBase64 + nonce + for (const otherNetworkName of otherNetworkNames) { + // Get wallet key and cert for other network's IIN Agent + const otherWallet = await getWalletForNetwork(otherNetworkName) + const otherKeyCert = await getKeyAndCertForRemoteRequestbyUserName(otherWallet, 'iinagent') + // Sign using wallet identity + let otherSecurityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() + otherSecurityDomainMember.setSecurityDomain(otherNetworkName) + otherSecurityDomainMember.setMemberId(getNetworkConfig(otherNetworkName).mspId) + let otherAttestation = new iin_agent_pb.Attestation() + otherAttestation.setUnitIdentity(otherSecurityDomainMember) + otherAttestation.setCertificate(otherKeyCert.cert) + const otherSig = InteroperableHelper.signMessage(serializedttestedMembershipSetBase64WithNonce, otherKeyCert.key.toBytes()) + otherAttestation.setSignature(otherSig) + otherAttestation.setNonce(nonce) + + // Generate chaincode argument and save it in a file + let counterAttestedMembership = new iin_agent_pb.CounterAttestedMembership() + counterAttestedMembership.setAttestedMembershipSet(serializedttestedMembershipSetBase64) + counterAttestedMembership.setAttestationsList( [ otherAttestation ] ) + + fs.writeFileSync( + path.join(credentialsPath, `attested-membership-${otherNetworkName}.proto.serialized`), + Buffer.from(counterAttestedMembership.serializeBinary()).toString('base64') + ) + } + } + } + return membershipJSON +} + +const formatMSP = (mspConfig: MspConfig, networkId: string) => { + const memberObject = { members: {}, securityDomain: networkId } + Object.entries(mspConfig).forEach(([name, value], _) => { + // const cert = Certificate.fromPEM(Buffer.from(value.root_certs[0], 'base64')) + memberObject.members[name] = { + type: 'ca', + value: Buffer.from(value.root_certs[0], 'base64').toString('utf8') + } + }) + return memberObject +} + +type MspConfig = { + [key: string]: { admins: any; root_certs: any; name: string } +} + +const getMspConfig = async ( + network, + logger: any = console +): Promise => { + const mspConfigs = network.channel.getMspids() + const orgMspConfig = {} + logger.debug(mspConfigs) + logger.debug(network.channel.getMsp(mspConfigs[0])) + + mspConfigs.forEach(mspId => { + if (mspId !== 'OrdererMSP') { + logger.info('Getting MSP Info for org with MSP ID: ' + mspId + '.') + const mspConfig = network.getChannel().getMsp(mspId) + delete mspConfig.id + if (Array.isArray(mspConfig.admins)) { + for (let i = 0; i < mspConfig.admins.length; i++) { + mspConfig.admins[i] = Buffer.from(mspConfig.admins[i]).toString( + 'base64' + ) + } + } else if (mspConfig.admins.length === 0) { + mspConfig.admins = [] + } else { + mspConfig.admins = [Buffer.from(mspConfig.admins).toString('base64')] + } + if (Array.isArray(mspConfig.rootCerts)) { + for (let i = 0; i < mspConfig.rootCerts.length; i++) { + mspConfig.rootCerts[i] = Buffer.from(mspConfig.rootCerts[i]).toString( + 'base64' + ) + } + } else if (mspConfig.rootCerts.length === 0) { + mspConfig.rootCerts = [] + } else { + mspConfig.rootCerts = [ + Buffer.from(mspConfig.rootCerts).toString('base64') + ] + } + mspConfig.root_certs = mspConfig.rootCerts + delete mspConfig.rootCerts + if (Array.isArray(mspConfig.intermediateCerts)) { + for (let i = 0; i < mspConfig.intermediateCerts.length; i++) { + mspConfig.intermediateCerts[i] = Buffer.from( + mspConfig.intermediateCerts[i] + ).toString('base64') + } + } else if (mspConfig.intermediateCerts.length === 0) { + mspConfig.intermediateCerts = [] + } else { + mspConfig.intermediateCerts = [ + Buffer.from(mspConfig.intermediateCerts).toString('base64') + ] + } + mspConfig.intermediate_certs = mspConfig.intermediateCerts + delete mspConfig.intermediateCerts + if (Array.isArray(mspConfig.tlsRootCerts)) { + for (let i = 0; i < mspConfig.tlsRootCerts.length; i++) { + mspConfig.tlsRootCerts[i] = Buffer.from( + mspConfig.tlsRootCerts[i] + ).toString('base64') + } + } else if (mspConfig.tlsRootCerts.length === 0) { + mspConfig.tlsRootCerts = [] + } else { + mspConfig.tlsRootCerts = [ + Buffer.from(mspConfig.tlsRootCerts).toString('base64') + ] + } + mspConfig.tls_root_certs = mspConfig.tlsRootCerts + delete mspConfig.tlsRootCerts + if (Array.isArray(mspConfig.tlsIntermediateCerts)) { + for (let i = 0; i < mspConfig.tlsIntermediateCerts.length; i++) { + mspConfig.tlsIntermediateCerts[i] = Buffer.from( + mspConfig.tlsIntermediateCerts[i] + ).toString('base64') + } + } else if (mspConfig.tlsIntermediateCerts.length === 0) { + mspConfig.tlsIntermediateCerts = [] + } else { + mspConfig.tlsIntermediateCerts = [ + Buffer.from(mspConfig.tlsIntermediateCerts).toString('base64') + ] + } + mspConfig.tls_intermediate_certs = mspConfig.tlsIntermediateCerts + delete mspConfig.tlsIntermediateCerts + orgMspConfig[mspId] = mspConfig + } + }) + return orgMspConfig +} + +async function fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + mspId = global.__DEFAULT_MSPID__, + logger = console, + discoveryEnabled = true, + userString = '', + userPwd = '', + registerUser = true +}: { + channel: string + contractName: string + connProfilePath: string + networkName: string + mspId?: string + discoveryEnabled?: boolean + logger?: any + userString?: string + userPwd?: string + registerUser?: boolean +}): Promise<{ gateway: Gateway; contract: Contract; wallet: any }> { + // load the network configuration + const ccpPath = path.resolve(__dirname, connProfilePath) + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) + // Create a new file system based wallet for managing identities. + // const walletPath = process.env.WALLET_PATH + // ? process.env.WALLET_PATH + // : path.join(__dirname, '../', `wallet-${networkName}`) + + if (!userString) { + userString = `user1` + userPwd = `user1pw` + } + + const wallet = await walletSetup(networkName, ccp, mspId, userString, userPwd, false, false, registerUser, logger) + // Check to see if we've already enrolled the user. + const identity = await wallet.get(userString) + if (!identity) { + logger.info( + `An identity for the user "${userString}" does not exist in the wallet` + ) + logger.info('Run the registerUser.ts application before retrying') + } + // Create a new gateway for connecting to our peer node. + const gateway = new Gateway() + await gateway.connect(ccp, { + wallet, + identity: identity, + discovery: { + enabled: discoveryEnabled, + asLocalhost: process.env.LOCAL === 'false' ? false : true + } + }) + const network = await gateway.getNetwork(channel) + // Get the contract from the network. + const contract = network.getContract(contractName) + return { gateway, contract, wallet } +} + +async function query( + invocationSpec: InvocationSpec, + connProfilePath: string, + networkName: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console, + userString = '', + registerUser = true +): Promise { + logger.debug('Running invoke on fabric network') + try { + logger.debug( + `QUERY: ${JSON.stringify( + invocationSpec + )} connProfilePath: ${connProfilePath} networkName ${networkName} ` + ) + const { contract, gateway } = await fabricHelper({ + channel: invocationSpec.channel, + contractName: invocationSpec.contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: mspId, + logger: logger, + userString: userString, + registerUser: registerUser + }) + const read = await contract.evaluateTransaction(invocationSpec.ccFunc, ...invocationSpec.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`State From Network:`, state) + } else { + logger.debug(`No State from network`) + } + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + logger.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +async function invoke( + invocationSpec: InvocationSpec, + connProfilePath: string, + networkName: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console, + userString = '', + registerUser = true +): Promise { + logger.debug('Running invoke on fabric network') + try { + const { contract, gateway } = await fabricHelper({ + channel: invocationSpec.channel, + contractName: invocationSpec.contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: mspId, + logger: logger, + userString: userString, + registerUser: registerUser + }) + logger.debug( + `CCFunc: ${invocationSpec.ccFunc} 'CCArgs: ${JSON.stringify(invocationSpec.args)}` + ) + const read = await contract.submitTransaction(invocationSpec.ccFunc, ...invocationSpec.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +const getKeyAndCertForRemoteRequestbyUserName = async ( + wallet: any, + username: string +): Promise<{ key: ICryptoKey; cert: any }> => { + if (!wallet) { + throw new Error('No wallet passed') + } + if (!username) { + throw new Error('No username passed') + } + const identity = await wallet.get(username) + if (!identity) { + throw new Error( + 'Identity for username ' + username + ' not present in wallet' + ) + } + // Assume the identity is of type 'fabric-network.X509Identity' + const privKey = Utils.newCryptoSuite().createKeyFromRaw( + identity.credentials.privateKey + ) + return { key: privKey, cert: identity.credentials.certificate } +} + +const getWalletForNetwork = async ( + networkName: string, +) => { + const walletPath = process.env.WALLET_PATH + ? process.env.WALLET_PATH + : path.join(__dirname, '../', `wallet-${networkName}`) + + const wallet = await Wallets.newFileSystemWallet(walletPath) + return wallet +} + + +export { + getUserCertBase64, + walletSetup, + invoke, + query, + enrollAndRecordWalletIdentity, + fabricHelper, + generateMembership, + generateAccessControl, + getKeyAndCertForRemoteRequestbyUserName, + getCredentialPath, + getCurrentNetworkCredentialPath, + generateVerificationPolicy +} diff --git a/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts b/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts new file mode 100644 index 0000000000..624164d8be --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts @@ -0,0 +1,764 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { getKeyAndCertForRemoteRequestbyUserName, fabricHelper, invoke, query, InvocationSpec } from './fabric-functions' +import { AssetPledge } from "@hyperledger/cacti-weaver-protos-js/common/asset_transfer_pb" +import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric' +import * as crypto from 'crypto' +import { promisify } from 'util' +import * as fs from 'fs' +import * as path from 'path' +import * as dotenv from 'dotenv' +import logger from './logger' +dotenv.config({ path: path.resolve(__dirname, '../../.env') }) + + +// UPDATE Following if new env variable or config variable is added. +// Valid keys for .env +const validKeys = [ + 'DEFAULT_CHANNEL', + 'DEFAULT_CHAINCODE', + 'MEMBER_CREDENTIAL_FOLDER', + 'LOCAL', + 'DEFAULT_APPLICATION_CHAINCODE', + 'CONFIG_PATH', + 'REMOTE_CONFIG_PATH', + 'CHAINCODE_PATH' +] +// Valid keys for config +const configKeys = ['connProfilePath', 'relayEndpoint', 'mspId', 'channelName', 'chaincode', 'aclPolicyPrincipalType'] + +const signMessage = (message, privateKey) => { + const sign = crypto.createSign('sha256') + sign.write(message) + sign.end() + return sign.sign(privateKey) +} + +// Basic function to add assets to network, it assumes function is CreateAsset +// TODO: Pass function name as parameter +const addAssets = ({ + dataFilePath, + networkName, + connProfilePath, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + channelName, + contractName, + ccFunc, + ccType, + logger +}: { + dataFilePath: string + networkName: string + connProfilePath: string + invocationSpec?: InvocationSpec + mspId?: string + channelName?: string + contractName?: string + ccFunc?: string + ccType: string + logger?: any +}): void => { + const filepath = path.resolve(dataFilePath) + const data = JSON.parse(fs.readFileSync(filepath).toString()) + const valuesList = Object.entries(data) + valuesList.forEach(async (item: [string, string]) => { + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: channelName, + contractName: contractName + ? contractName + : 'simpleasset', + ccFunc: '', + args: [] + } + + const { gateway, contract, wallet } = await fabricHelper({ + channel: channelName, + contractName: contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: mspId, + userString: item[1]['owner'], + registerUser: false + }) + const userId = await wallet.get(item[1]['owner']) + const userCert = Buffer.from((userId).credentials.certificate).toString('base64') + + if (ccType == 'bond') { + currentQuery.ccFunc = 'CreateAsset' + currentQuery.args = [...currentQuery.args, item[1]['assetType'], item[1]['id'], userCert, item[1]['issuer'], item[1]['facevalue'], item[1]['maturitydate']] + } else if (ccType == 'token') { + currentQuery.ccFunc = 'IssueTokenAssets' + currentQuery.args = [...currentQuery.args, item[1]['tokenassettype'], item[1]['numunits'], userCert] + } else { + throw new Error(`Unrecognized asset category: ${ccType}`) + } + console.log(currentQuery) + try { + const read = await contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } + }) +} + + +// Basic function to pledge an asset in one network to another, it assumes function is PledgeAsset +// TODO: Pass function name as parameter +const pledgeAsset = async ({ + dataFilePath, + sourceNetworkName, + destNetworkName, + recipient, + expirySecs, + connProfilePath, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + channelName, + contractName, + ccFunc, + ccType, + assetOwner, + assetRef, + assetUnits, + logger +}: { + dataFilePath: string + sourceNetworkName: string + destNetworkName: string + recipient: string + expirySecs: number + connProfilePath: string + invocationSpec?: InvocationSpec + mspId?: string + channelName?: string + contractName?: string + ccFunc?: string + ccType: string + assetOwner: string + assetRef: string + assetUnits: number + logger?: any +}): Promise => { + const filepath = path.resolve(dataFilePath) + const data = JSON.parse(fs.readFileSync(filepath).toString()) + let item + if (assetRef) { + item = data[assetRef] + if (!item) { + throw new Error(`Cannot find asset ref ${assetRef} in file ${filepath}`) + } + } else if (assetOwner) { + item = data[assetOwner] + if (!item) { + throw new Error(`Cannot find asset owner ${assetOwner} in file ${filepath}`) + } + } else { + throw new Error(`Neither asset owner nor reference is supplied`) + } + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: channelName, + contractName: contractName + ? contractName + : 'simpleasset', + ccFunc: '', + args: [] + } + + const { gateway, contract, wallet } = await fabricHelper({ + channel: channelName, + contractName: contractName, + connProfilePath: connProfilePath, + networkName: sourceNetworkName, + mspId: mspId, + userString: item['owner'], + registerUser: false + }) + const recipientCert = getUserCertFromFile(recipient, destNetworkName) + const expirationTime = (Math.floor(Date.now()/1000 + expirySecs)).toString() + + if (ccType == 'bond') { + currentQuery.ccFunc = 'PledgeAsset' + currentQuery.args = [...currentQuery.args, item['assetType'], item['id'], destNetworkName, recipientCert, expirationTime] + } else if (ccType == 'token') { + currentQuery.ccFunc = 'PledgeTokenAsset' + currentQuery.args = [...currentQuery.args, item['tokenassettype'], '' + assetUnits, destNetworkName, recipientCert, expirationTime] + } else { + throw new Error(`Unrecognized/unsupported asset category: ${ccType}`) + } + console.log(currentQuery) + try { + const read = await contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +// Used to obtain remote network user certificate from '${networkId}_UsersAndCerts.json' file. +// This is called during Pledge to get the recipientCert, and during Claim to get the pledgerCert. +const getUserCertFromFile = ( + remoteUser: string, + remoteNetworkId: string +) => { + const usersAndCertsFile = remoteNetworkId + '_UsersAndCerts.json' + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, '..') + : path.join(__dirname, '../data', 'credentials', '..') + try { + const dirPath = path.resolve(credentialsPath, 'remoteNetworkUsers') + const filepath = path.resolve(dirPath, usersAndCertsFile) + const usersAndCertsJSON = JSON.parse(fs.readFileSync(filepath).toString()) + logger.debug(`credentialsPath: ${credentialsPath} and usersAndCertsFile: ${usersAndCertsFile}`) + + if (!usersAndCertsJSON[remoteUser]) { + logger.error( + `User: ${remoteUser} does not exist in the file ${usersAndCertsFile}.` + ) + return '' + } + logger.debug(`remoteUser: ${remoteUser} and certificate: ${usersAndCertsJSON[remoteUser]}`) + return usersAndCertsJSON[remoteUser] + } catch (err) { + logger.error(`User: ${remoteUser} does not exist in the file ${usersAndCertsFile}.`) + return '' + } +} + +// Used to store the network user certificate to the file '${networkId}_UsersAndCerts.json'. +// This is used during Pledge to get the recipientCert, and during Claim to get the pledgerCert. +const saveUserCertToFile = ( + remoteUser: string, + remoteNetworkId: string +) => { + const usersAndCertsFile = remoteNetworkId + '_UsersAndCerts.json' + let usersAndCertsJSON = {} + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, '..') + : path.join(__dirname, '../data', 'credentials', '..') + // Don't create the directory 'remoteNetworkUsers' inside 'data/credentials' since each entry there represents + // a network. Instead, create this directory inside 'data' itself. + try { + const dirPath = path.resolve(credentialsPath, 'remoteNetworkUsers') + const filepath = path.resolve(dirPath, usersAndCertsFile) + logger.debug(`credentialsPath: ${credentialsPath} and usersAndCertsFile: ${usersAndCertsFile}`) + + if (!fs.existsSync(dirPath)) { + logger.debug(`Creating directory ${dirPath}`) + fs.mkdirSync(dirPath, { recursive: true }) + } + + if (fs.existsSync(filepath)) { + logger.debug(`Reading contents of the file ${filepath}`) + usersAndCertsJSON = JSON.parse(fs.readFileSync(filepath).toString()) + } + + const remoteUserId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + remoteNetworkId + '/' + remoteUser + '.id').toString()) + const remoteUserCertBase64 = Buffer.from(remoteUserId.credentials.certificate).toString('base64') + + usersAndCertsJSON[remoteUser] = remoteUserCertBase64 + fs.writeFileSync( + path.resolve(filepath), + JSON.stringify(usersAndCertsJSON) + ) + } catch (err) { + logger.error(`User: ${remoteUser} certificate cannot be saved to the file ${usersAndCertsFile}.`) + } +} + +// Basic function to query asset pledge details from a network, it assumes function is GetAssetPledgeStatus +// TODO: Pass function name as parameter +const getAssetPledgeDetails = async ({ + sourceNetworkName, + pledger, + pledgerCert, + destNetworkName, + recipient, + recipientCert, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + ccFunc, + pledgeId, + logger +}: { + sourceNetworkName: string + pledger: string + pledgerCert: string + destNetworkName: string + recipient: string + recipientCert: string + invocationSpec?: InvocationSpec + mspId?: string + ccFunc?: string + pledgeId: string + logger?: any +}): Promise => { + const netConfig = getNetworkConfig(sourceNetworkName) + + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: netConfig.channelName, + contractName: netConfig.chaincode + ? netConfig.chaincode + : 'simpleasset', + ccFunc: '', + args: [] + } + + const { gateway, contract, wallet } = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: sourceNetworkName, + mspId: netConfig.mspId, + userString: pledger, + registerUser: false + }) + if (!pledgerCert) { + const pledgerId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + sourceNetworkName + '/' + pledger + '.id').toString()) + pledgerCert = Buffer.from(pledgerId.credentials.certificate).toString('base64') + } + if (!recipientCert) { + const recipientId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + destNetworkName + '/' + recipient + '.id').toString()) + recipientCert = Buffer.from(recipientId.credentials.certificate).toString('base64') + } + + currentQuery.ccFunc = 'GetAssetPledgeStatus' + currentQuery.args = [...currentQuery.args, pledgeId, pledgerCert, destNetworkName, recipientCert] + console.log(currentQuery) + try { + const read = await contract.evaluateTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +// Basic function to query asset pledge details from a network, it assumes function is GetAssetPledgeDetails +// TODO: Pass function name as parameter +const getLocalAssetPledgeDetails = async ({ + sourceNetworkName, + pledgeId, + caller, + ccType, + ccFunc, + logger +}: { + sourceNetworkName: string + pledgeId: string + caller: string + ccType?: string + ccFunc?: string + logger?: any +}): Promise => { + const netConfig = getNetworkConfig(sourceNetworkName) + + const currentQuery = { + channel: netConfig.channelName, + contractName: netConfig.chaincode + ? netConfig.chaincode + : 'simpleasset', + ccFunc: '', + args: [] + } + + if (ccFunc) { + currentQuery.ccFunc = ccFunc + } else if (ccType && ccType == 'token') { + currentQuery.ccFunc = 'GetTokenAssetPledgeDetails' + } else { + currentQuery.ccFunc = 'GetAssetPledgeDetails' + } + currentQuery.args = [...currentQuery.args, pledgeId] + console.log(currentQuery) + try { + const pledgeDetails = await query(currentQuery, + netConfig.connProfilePath, + sourceNetworkName, + netConfig.mspId, + logger, + caller, + false + ) + const pledgeDetailBytes = Buffer.from(pledgeDetails, 'base64') + const pledgeDetailsProto = AssetPledge.deserializeBinary(pledgeDetailBytes) + return pledgeDetailsProto + } catch (error) { + console.error(`Failed to get pledge details: ${error}`) + throw new Error(error) + } +} + +// Basic function to add data to network, it assumes function is Create +// TODO: Pass function name as parameter +const addData = ({ + filename, + networkName, + connProfilePath, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + logger +}: { + filename: string + networkName: string + connProfilePath: string + invocationSpec?: InvocationSpec + mspId?: string + logger?: any +}): void => { + const filepath = path.resolve(__dirname, '..', 'data', filename) + const data = JSON.parse(fs.readFileSync(filepath).toString()) + const valuesList = Object.entries(data) + valuesList.forEach((item: [string, string]) => { + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: process.env.DEFAULT_CHANNEL + ? process.env.DEFAULT_CHANNEL + : 'mychannel', + contractName: process.env.DEFAULT_APPLICATION_CHAINCODE + ? process.env.DEFAULT_APPLICATION_CHAINCODE + : 'simplestate', + ccFunc: process.env.DEFAULT_APPLICATION_FUNC + ? process.env.DEFAULT_APPLICATION_FUNC + : 'Create', + args: [] + } + currentQuery.args = [...currentQuery.args, item[0], item[1]] + invoke(currentQuery, connProfilePath, networkName, mspId, logger) + }) +} + +// A better way to handle errors for promises +function handlePromise(promise: Promise): Promise<[T?, Error?]> { + const result: Promise<[T?, Error?]> = promise + .then(data => { + const response: [T?, Error?] = [data, undefined] + return response + }) + .catch(error => Promise.resolve([undefined, error])) + return result +} + +// Necessary until gRPC provides a native async friendly solution https://github.com/grpc/grpc-node/issues/54 +function promisifyAll(client): any { + const to = {} + for (const k in client) { + if (typeof client[k] != 'function') continue + to[k] = promisify(client[k].bind(client)) + } + return to +} + +const readJSONFromFile = (jsonfile, logger = console) => { + let data = null + const filepath = path.resolve(jsonfile) + logger.debug('jsonfile is ' + jsonfile) + logger.debug('filepath is ' + filepath) + + try { + const contents = fs.readFileSync(filepath).toString() + logger.debug('contents ' + contents) + data = JSON.parse(contents) + logger.debug('data - ' + JSON.stringify(data)) + } catch (e) { + logger.debug('Error ' + e.message + ' while parsing JSON config file') + throw e + } + return data +} + +// Used for getting network configuration from config.json file. +const getNetworkConfig = ( + networkId: string +): { relayEndpoint?: string; connProfilePath: string; username?: string; mspId?:string; aclPolicyPrincipalType?: string; channelName?: string; chaincode?: string } => { + const configPath = process.env.CONFIG_PATH + ? path.join(process.env.CONFIG_PATH) + : path.join(__dirname, '../../config.json') + try { + const configJSON = JSON.parse(fs.readFileSync(configPath).toString()) + if (!configJSON[networkId]) { + logger.error( + `Network: ${networkId} does not exist in the config.json file` + ) + return { relayEndpoint: '', connProfilePath: '', username: '', mspId: '', aclPolicyPrincipalType: '', channelName: '', chaincode: '' } + } + return configJSON[networkId] + } catch (err) { + logger.error(`Network: ${networkId} does not exist in the config.json file`) + return { relayEndpoint: '', connProfilePath: '', username: '', mspId: '', aclPolicyPrincipalType: '', channelName: '', chaincode: '' } + } +} + +// Used for getting network configuration from config.json file. +const getChaincodeConfig = ( + chaincodeId: string, + chaincodeFunc: string +): { args: Array; replaceIndices: Array } => { + const ccPath = process.env.CHAINCODE_PATH + ? path.join(process.env.CHAINCODE_PATH) + : path.join(__dirname, '../../chaincode.json') + try { + const ccJSON = JSON.parse(fs.readFileSync(ccPath).toString()) + if (!ccJSON[chaincodeId]) { + logger.error( + `Chaincode: ${chaincodeId} does not exist in the chaincode.json file` + ) + return { args: [], replaceIndices: [] } + } + if (!ccJSON[chaincodeId][chaincodeFunc]) { + logger.error( + `Chaincode: ${chaincodeId} does not have a ${chaincodeFunc} function attribute in the chaincode.json file` + ) + return { args: [], replaceIndices: [] } + } + return ccJSON[chaincodeId][chaincodeFunc] + } catch (err) { + logger.error(`Chaincode: ${chaincodeId} does not exist in the chaincode.json file`) + return { args: [], replaceIndices: [] } + } +} + +// Update view address if needed +const generateViewAddress = async ( + viewAddress: string, + sourceNetwork: string, + destNetwork: string, + logger?: any +): Promise => { + if (!viewAddress || viewAddress.length === 0) { + throw new Error('Empty view address') + } + if (viewAddress.indexOf('#') >= 0) { + return viewAddress + } + if (viewAddress.indexOf('GetAssetClaimStatus') >= 0 || viewAddress.indexOf('GetTokenAssetClaimStatus') >= 0) { + // Get asset pledge details + let ccFunc + if (viewAddress.indexOf('GetAssetClaimStatus') >= 0) { + ccFunc = 'GetAssetClaimStatus' + } else { + ccFunc = 'GetTokenAssetClaimStatus' + } + const addressParts = viewAddress.substring(viewAddress.indexOf(ccFunc) + ccFunc.length + 1).split(':') + if (addressParts.length != 6) { + throw new Error(`Expected 6 arguments for ${ccFunc}; found ${addressParts.length}`) + } + if (addressParts[5] != sourceNetwork) { + throw new Error(`Passed source network ID ${sourceNetwork} does not match last chaincode argument in view address ${addressParts[5]}`) + } + const pledgeDetails = await getAssetPledgeDetails({ + sourceNetworkName: addressParts[5], + pledger: '', + pledgerCert: addressParts[4], + destNetworkName: destNetwork, + recipient: '', + recipientCert: addressParts[3], + pledgeId: addressParts[0], + logger: logger + }) + return viewAddress + ':' + deserializeAssetPledge(pledgeDetails).getExpirytimesecs() + } else { + return viewAddress + } +} + +function deserializeAssetPledge(pledgeDetails) { + const pledgeDetailBytes = Buffer.from(pledgeDetails, 'base64') + const pledgeDetailsProto = AssetPledge.deserializeBinary(pledgeDetailBytes) + return pledgeDetailsProto +} + +// Used for creating view address for interop call using remote-network-config.json +const generateViewAddressFromRemoteConfig = ( + networkId: string, + funcName: string, + funcArgs: Array +): any => { + const configPath = process.env.REMOTE_CONFIG_PATH + ? path.join(process.env.REMOTE_CONFIG_PATH) + : path.join(__dirname, '../../remote-network-config.json') + try { + const configJSON = JSON.parse(fs.readFileSync(configPath).toString()) + if (!configJSON[networkId]) { + logger.error( + `Error: ${networkId} does not exist in the remote-network-config.json file` + ) + throw new Error(`Error: ${networkId} does not exist in the remote-network-config.json file`) + } + + const remoteNetConfig = configJSON[networkId] + let address = remoteNetConfig.relayEndpoint + '/' + networkId + if (remoteNetConfig.type == "fabric") { + address = address + '/' + remoteNetConfig.channelName + ':' + + remoteNetConfig.chaincode + ':' + funcName + ':' + funcArgs.join(':') + } else if (remoteNetConfig.type == "corda") { + address = address + '/' + remoteNetConfig.partyEndPoint + '#' + + remoteNetConfig.flowPackage + "." + funcName + ":" + funcArgs.join(':') + } else { + logger.error(`Error: remote network ${remoteNetConfig.type} not supported.`) + throw new Error(`Error: remote network ${remoteNetConfig.type} not supported.`) + } + console.log(`Interop query, funcName: ${funcName} \n funcArgs: ${funcArgs} \n and address: ${address}`) + + return address + } catch (err) { + logger.error(`Error: ${err}`) + throw new Error(err) + } +} + + +// Used for creating view address for interop call using remote-network-config.json +const interopHelper = async ( + networkName: string, + viewAddress: string, + appChaincodeId: string, + applicationFunction: string, + applicationArgs: Array, + replaceIndices: Array, + options: any, // For TLS +): Promise => { + const netConfig = getNetworkConfig(networkName) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + throw new Error(`No valid config entry found for ${networkName}`) + } + + const { gateway, wallet, contract } = await fabricHelper({ + channel: netConfig.channelName, + contractName: process.env.DEFAULT_CHAINCODE ? process.env.DEFAULT_CHAINCODE : 'interop', + connProfilePath: netConfig.connProfilePath, + networkName, + mspId: netConfig.mspId, + logger, + discoveryEnabled: true, + userString: options['user'] + }) + + const [keyCert, keyCertError] = await handlePromise( + getKeyAndCertForRemoteRequestbyUserName(wallet, options['user']) + ) + if (keyCertError) { + throw new Error(`Error getting key and cert ${keyCertError}`) + } + logger.info(`Starting Interop Query`) + + let relayTlsCAFiles = [] + if (options['relay-tls-ca-files']) { + relayTlsCAFiles = options['relay-tls-ca-files'].split(':') + } + try { + const invokeObject = { + channel: netConfig.channelName, + ccFunc: applicationFunction, + ccArgs: applicationArgs, + contractName: appChaincodeId + } + console.log(invokeObject) + const interopFlowResponse = await InteroperableHelper.interopFlow( + //@ts-ignore this comment can be removed after using published version of interop-sdk + contract, + networkName, + invokeObject, + netConfig.mspId, + netConfig.relayEndpoint, + replaceIndices, + [{ + address: viewAddress, + Sign: true + }], + keyCert, + [], + false, + options['relay-tls'] === 'true', + relayTlsCAFiles, + options['e2e-confidentiality'] === 'true', + gateway + ) + logger.info( + `View from remote network: ${JSON.stringify( + interopFlowResponse.views[0].toObject() + )}. Interop Flow result: ${interopFlowResponse.result || 'successful'}` + ) + logger.debug(`ViewB64: ${Buffer.from(interopFlowResponse.views[0].serializeBinary()).toString('base64')}`) + const remoteValue = (options['e2e-confidentiality'] === 'true' ? + InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0], keyCert.key.toBytes()) : + InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0]) + ) + if (remoteValue.contents) { + logger.debug(`ViewB64Contents: ${Buffer.from(remoteValue.contents).toString('base64')}`) + } + logger.info( + `Called Function ${applicationFunction}. With Args: ${invokeObject.ccArgs} ${remoteValue.data}` + ) + await gateway.disconnect() + return remoteValue.data + } catch (e) { + logger.error(`Error verifying and storing state`) + logger.error(`Error verifying and storing state: ${e}`) + return "" + } +} + + + +export { + addData, + handlePromise, + promisifyAll, + readJSONFromFile, + signMessage, + getNetworkConfig, + getUserCertFromFile, + saveUserCertToFile, + getChaincodeConfig, + validKeys, + configKeys, + addAssets, + pledgeAsset, + getAssetPledgeDetails, + getLocalAssetPledgeDetails, + generateViewAddress, + generateViewAddressFromRemoteConfig, + interopHelper +} diff --git a/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts b/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts new file mode 100644 index 0000000000..b85bbc1db6 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts @@ -0,0 +1,230 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as fs from 'fs' +import * as path from 'path' +import { + invoke, + getCurrentNetworkCredentialPath, + getCredentialPath, + fabricHelper +} from '../fabric-functions' +import { handlePromise, getNetworkConfig } from '../helpers' +import { MembershipManager } from '@hyperledger/cacti-weaver-sdk-fabric' + +const helperInvoke = async (userId, ccFunc, ccArg, ...args) => { + const [contractName, channelName, connProfilePath, networkName, logger] = args + const [invokeResponse, invokeError] = await handlePromise( + invoke( + { + contractName, + channel: channelName, + ccFunc: ccFunc, + args: [ccArg] + }, + connProfilePath, + networkName, + global.__DEFAULT_MSPID__, + logger, + userId, + (userId === '') + ) + ) + logger.debug(`${ccFunc} Invoke ${JSON.stringify(invokeResponse)}`) + if (invokeError) { + logger.error(`${ccFunc} Invoke Error: ${ccFunc}: ${ccArg}`) + throw new Error(`${ccFunc} Invoke Error ${invokeError}`) + } else { + logger.info(`Successfully invoked ${ccFunc}`) + } +} + +const configureNetwork = async (mainNetwork: string, members: Array = [global.__DEFAULT_MSPID__], logger: any = console, iinAgent: boolean = false) => { + const networkEnv = getNetworkConfig(mainNetwork) + logger.debug(`NetworkEnv: ${JSON.stringify(networkEnv)}`) + if (!networkEnv.relayEndpoint || !networkEnv.connProfilePath) { + logger.error( + 'Please use a valid --local-network. If valid network please check if your environment variables are configured properly' + ) + return + } + + const credentialFolderPath = getCredentialPath() + const networkFolders = fs + .readdirSync(credentialFolderPath, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .map(item => item.name) + // Reorder the array so that the local network is the first element + // We need to record local membership before recording other networks' memberships + networkFolders.splice(networkFolders.indexOf(mainNetwork), 1) + networkFolders.splice(0, 0, mainNetwork) + + for (const index in networkFolders) { + const network = networkFolders[index] + if (network === mainNetwork) { + // A network needs to load/record only other networks' credentials + await loadLocalHelper( + networkEnv.connProfilePath, + mainNetwork, + process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', + process.env.DEFAULT_CHAINCODE + ? process.env.DEFAULT_CHAINCODE + : 'interop', + members, + logger + ) + continue; + } + const accessControlPath = path.join( + getCurrentNetworkCredentialPath(network), + 'access-control.json' + ) + let membershipPath = "" + if (!network.startsWith('network')) { + membershipPath = path.join( + getCurrentNetworkCredentialPath(network), + 'membership.json' + ) + } else if (iinAgent) { + membershipPath = path.join( + getCurrentNetworkCredentialPath(network), + 'attested-membership-' + mainNetwork + '.proto.serialized' + ) + } + const verificationPolicyPath = path.join( + getCurrentNetworkCredentialPath(network), + 'verification-policy.json' + ) + if ( + !fs.existsSync(accessControlPath) || + !fs.existsSync(verificationPolicyPath) || + (membershipPath !== "" && !fs.existsSync(membershipPath)) + ) { + logger.error(`Missing credential file for network: ${network}`) + } else { + await configureNetworkHelper( + networkEnv.connProfilePath, + mainNetwork, + process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', + process.env.DEFAULT_CHAINCODE + ? process.env.DEFAULT_CHAINCODE + : 'interop', + network, + accessControlPath, + membershipPath, + verificationPolicyPath, + logger, + iinAgent + ) + } + } +} + +const loadLocalHelper = async ( + connProfilePath: string, + networkName: string, + channelName: string, + contractName: string, + members: Array, + logger: any = console +): Promise => { + //const localMembership = Buffer.from(fs.readFileSync(localMembershipPath)).toString() + const { gateway } = await fabricHelper({ + channel: channelName, + contractName: contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: global.__DEFAULT_MSPID__, + userString: 'networkadmin', + registerUser: false + }) + try { + const response = await MembershipManager.createLocalMembership(gateway, members, networkName, channelName, contractName) + logger.info('CreateLocalMembership Successful.') + } catch (e) { + logger.error(e) + logger.info('CreateLocalMembership attempting Update') + const response = await MembershipManager.updateLocalMembership(gateway, members, networkName, channelName, contractName) + logger.info('Update Local Memebrship response: success: ', response) + } +} + +const configureNetworkHelper = async ( + connProfilePath: string, + networkName: string, + channelName: string, + contractName: string, + targetNetwork: string, + accessControlPath: string, + membershipPath: string, + verificationPolicyPath: string, + logger: any = console, + iinAgent: boolean = false +): Promise => { + logger.info(`Target Network: ${targetNetwork}`) + const accessControl = Buffer.from( + fs.readFileSync(accessControlPath) + ).toString() + + const verificationPolicy = Buffer.from( + fs.readFileSync(verificationPolicyPath) + ).toString() + + const helperInvokeArgs = [ + contractName, + channelName, + connProfilePath, + networkName, + logger + ] + + const adminUser = 'networkadmin' + + try { + await helperInvoke( + adminUser, + 'CreateAccessControlPolicy', + accessControl, + ...helperInvokeArgs + ) + } catch (e) { + logger.info('CreateAccessControlPolicy attempting Update') + await helperInvoke( + adminUser, + 'UpdateAccessControlPolicy', + accessControl, + ...helperInvokeArgs + ) + } + try { + await helperInvoke( + adminUser, + 'CreateVerificationPolicy', + verificationPolicy, + ...helperInvokeArgs + ) + } catch (e) { + logger.info('CreateVerificationPolicy attempting Update') + await helperInvoke( + adminUser, + 'UpdateVerificationPolicy', + verificationPolicy, + ...helperInvokeArgs + ) + } + if (iinAgent || !targetNetwork.startsWith('network')) { + const membership = Buffer.from(fs.readFileSync(membershipPath)).toString() + const memberRecordingUser = iinAgent ? 'iinagent': adminUser // HACK until we add IIN Agents for Corda networks + try { + await helperInvoke(memberRecordingUser, 'CreateMembership', membership, ...helperInvokeArgs) + } catch (e) { + logger.info('CreateMembership attempting Update') + await helperInvoke(memberRecordingUser, 'UpdateMembership', membership, ...helperInvokeArgs) + } + } +} + +export { configureNetworkHelper, configureNetwork } diff --git a/weaver/core/drivers/fabric-driver/server/helpers/logger.ts b/weaver/core/drivers/fabric-driver/server/helpers/logger.ts new file mode 100644 index 0000000000..7b14c5a377 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/logger.ts @@ -0,0 +1,29 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as winston from 'winston' +import * as path from 'path' +const { format, transports } = winston + +const logFormat = format.printf( + info => `${info.timestamp} ${info.level} [${info.label}]: ${info.message}` +) + +const logger = winston.createLogger({ + format: format.combine( + format.label({ label: path.basename(process.mainModule.filename) }), + format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), + format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] }) + ), + transports: [ + new transports.Console({ + format: format.combine(format.colorize(), logFormat) + }) + ], + exitOnError: false +}) + +export default logger diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts new file mode 100644 index 0000000000..d0240049d6 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -0,0 +1,196 @@ +import ack_pb from '@hyperledger/cacti-weaver-protos-js/common/ack_pb'; +import eventsPb from '@hyperledger/cacti-weaver-protos-js/common/events_pb'; +import events_grpc_pb from '@hyperledger/cacti-weaver-protos-js/relay/events_grpc_pb'; +import queryPb from '@hyperledger/cacti-weaver-protos-js/common/query_pb'; +import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric'; +import { getDriverKeyCert } from "./walletSetup"; +import { DBConnector, DBKeyNotFoundError, LevelDBConnector } from "./dbConnector"; +import { checkIfArraysAreEqual, handlePromise, relayCallback } from "./utils"; +import { registerListenerForEventSubscription, unregisterListenerForEventSubscription } from "./listener"; +import { getNetworkGateway } from "./fabric-code"; +import { Gateway, Network, Contract } from "fabric-network"; +import state_pb from '@hyperledger/cacti-weaver-protos-js/common/state_pb'; +import driverPb from '@hyperledger/cacti-weaver-protos-js/driver/driver_pb'; +import logger from './logger'; + +import { getNetworkConfig } from './helpers/helpers' +import { AssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' + +import fs from 'fs'; +import path from 'path'; +import { fabricHelper } from './helpers/fabric-functions'; + +const DB_NAME: string = "driverdb"; +const DRIVER_ERROR_CONSTANTS = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../constants/driver-error-constants.json'), + ).toString(), +); + +async function performLockHelper( + performLockRequest: driverPb.PerformLockRequest, + networkName: string +): Promise { + + + // Locker and Recipient + const locker = performLockRequest['locker']; + const recipient = performLockRequest['recipient']; + let hashFn = performLockRequest['hash_fn']; + let hashBase64 = performLockRequest['hashBase64']; + + // Hash + let hash: HashFunctions.Hash + if (hashFn == 'SHA512') { + hash = new HashFunctions.SHA512() + } else { + hash = new HashFunctions.SHA256() + } + + if (hashBase64) { + hash.setSerializedHashBase64(hashBase64) + } + else { + logger.info(`No hash provided, using random preimage`) + } + + // Timeout + var timeout = 0, timeout2 = 0; + const currTime = Math.floor(Date.now() / 1000); + if (performLockRequest['timeout-epoch']) { + let duration = performLockRequest['timeout-epoch'] - currTime + timeout = performLockRequest['timeout-epoch'] + timeout2 = performLockRequest['timeout-epoch'] + duration + } + else if (performLockRequest['timeout-duration']) { + timeout = currTime + performLockRequest['timeout-duration'] + timeout2 = currTime + 2 * performLockRequest['timeout-duration'] + } + + const params = performLockRequest['param'].split(':') + + const netConfig = getNetworkConfig(performLockRequest['target-network']) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + console.error( + `Please use a valid --target-network. No valid environment found for ${performLockRequest['target-network']} ` + ) + return + } + + const network = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: performLockRequest['target-network'], + mspId: netConfig.mspId, + userString: locker + }) + + const lockerId = await network.wallet.get(locker) + const lockerCert = Buffer.from((lockerId).credentials.certificate).toString('base64') + + const recipientId = await network.wallet.get(recipient) + const recipientCert = Buffer.from((recipientId).credentials.certificate).toString('base64') + + var funcToCall, asset + + if (performLockRequest['fungible']) { + funcToCall = AssetManager.createFungibleHTLC + asset = 'Fungible Asset' + } else { + funcToCall = AssetManager.createHTLC + asset = 'Asset' + } + + console.info(`Asset Exchange: Lock ${asset}:\n`); + + try { + console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) + const res = await funcToCall(network.contract, + params[0], + params[1], + recipientCert, + hash, + timeout, + null) + if (!res.result) { + throw new Error() + } + console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) + console.info('Asset Exchange: Lock Complete.') + } catch (error) { + console.error(`Could not Lock ${asset} in ${performLockRequest['target-network']}`) + } + + // await new Promise(f => setTimeout(f, performLockRequest['timeout-duration'] * 1000 + 3000)); + + await network.gateway.disconnect() + console.log('Gateways disconnected.') + + + // const viewPayload: state_pb.ViewPayload = performLockRequest.getViewPayload(); + // const ctx: eventsPb.ContractTransaction = writeExternalStateMessage.getCtx(); + // const keyCert = await getDriverKeyCert(); + + // const requestId: string = viewPayload.getRequestId(); + // if (!viewPayload.getError()) { + + // let interopArgIndices = [], viewsSerializedBase64 = [], addresses = [], viewContentsBase64 = []; + // const view: state_pb.View = viewPayload.getView(); + + // const result = InteroperableHelper.getResponseDataFromView(view, keyCert.key.toBytes()); + // if (result.contents) { + // viewContentsBase64.push(result.contents); + // } else { + // viewContentsBase64.push([]); + // } + + // interopArgIndices.push(ctx.getReplaceArgIndex()); + // addresses.push(result.viewAddress); + // viewsSerializedBase64.push(Buffer.from(viewPayload.getView().serializeBinary()).toString("base64")); + + // let ccArgsB64 = ctx.getArgsList(); + // let ccArgsStr = []; + // for (const ccArgB64 of ccArgsB64) { + // ccArgsStr.push(Buffer.from(ccArgB64).toString('utf8')); + // } + + // let gateway: Gateway = await getNetworkGateway(networkName); + // const network: Network = await gateway.getNetwork(ctx.getLedgerId()); + // const interopContract: Contract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); + + // const endorsingOrgs = ctx.getMembersList(); + // const invokeObject = { + // channel: ctx.getLedgerId(), + // ccFunc: ctx.getFunc(), + // ccArgs: ccArgsStr, + // contractName: ctx.getContractId() + // } + // logger.info(`writing external state to contract: ${ctx.getContractId()} with function: ${ctx.getFunc()}, and args: ${invokeObject.ccArgs} on channel: ${ctx.getLedgerId()}`); + + // const [ response, responseError ] = await handlePromise(InteroperableHelper.submitTransactionWithRemoteViews( + // interopContract, + // invokeObject, + // interopArgIndices, + // addresses, + // viewsSerializedBase64, + // viewContentsBase64, + // endorsingOrgs + // )); + // if (responseError) { + // logger.error(`Failed writing to the ledger with error: ${responseError}`); + // gateway.disconnect(); + // throw responseError; + // } + // logger.debug(`write successful`); + // gateway.disconnect(); + // } else { + // const errorString: string = `erroneous viewPayload identified in WriteExternalState processing`; + // logger.error(`error viewPayload.getError(): ${JSON.stringify(viewPayload.getError())}`); + // throw new Error(errorString); + // } +} + +export { + performLockHelper +} diff --git a/weaver/core/drivers/fabric-driver/server/server.ts b/weaver/core/drivers/fabric-driver/server/server.ts index c645caece3..d31c7805ff 100644 --- a/weaver/core/drivers/fabric-driver/server/server.ts +++ b/weaver/core/drivers/fabric-driver/server/server.ts @@ -19,6 +19,7 @@ import 'dotenv/config'; import { loadEventSubscriptionsFromStorage, monitorBlockForMissedEvents } from './listener' import { walletSetup } from './walletSetup'; import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery, writeExternalStateHelper } from "./events" +import { performLockHelper } from "./satp" import * as path from 'path'; import { handlePromise, relayCallback, getRelayClientForQueryResponse, getRelayClientForEventSubscription, delay } from './utils'; import { dbConnectionTest, eventSubscriptionTest } from "./tests" @@ -233,6 +234,27 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { callback(null, ack_err_response); }); }, + performLock: (call: { request: driverPb.PerformLockRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + performLockHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully written to the ledger'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, }); // Prepares required crypto material for communication with the fabric network diff --git a/weaver/core/relay/config/Dummy_Relay.toml b/weaver/core/relay/config/Dummy_Relay.toml index 125d18af27..bacb83f1fa 100644 --- a/weaver/core/relay/config/Dummy_Relay.toml +++ b/weaver/core/relay/config/Dummy_Relay.toml @@ -53,6 +53,6 @@ tls=false tlsca_cert_path="credentials/fabric_ca_cert.pem" [drivers.Dummy] hostname="localhost" -port="9092" +port="9090" tls=false tlsca_cert_path="credentials/fabric_ca_cert.pem" From 1e53b2d1c95dae915730906882a929393b985bf8 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Wed, 23 Aug 2023 12:20:05 +0100 Subject: [PATCH 22/59] Added the required functions to call back the gateway after the asset is locked. --- weaver/common/protos-go/build-protos.sh | 2 +- weaver/common/protos-js/build-protos.sh | 4 +- .../core/drivers/fabric-driver/server/satp.ts | 190 ++++++++---------- 3 files changed, 88 insertions(+), 108 deletions(-) diff --git a/weaver/common/protos-go/build-protos.sh b/weaver/common/protos-go/build-protos.sh index fafd90a297..44589e706d 100644 --- a/weaver/common/protos-go/build-protos.sh +++ b/weaver/common/protos-go/build-protos.sh @@ -8,6 +8,6 @@ protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go_out=$BUILDDIR protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go_out=$BUILDDIR --go_opt=paths=source_relative $PROTOSDIR/fabric/view_data.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go_out=$BUILDDIR --go_opt=paths=source_relative $PROTOSDIR/corda/view_data.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/networks/networks.proto -protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto PROTOSDIR/relay/satp.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/driver/driver.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/identity/agent.proto diff --git a/weaver/common/protos-js/build-protos.sh b/weaver/common/protos-js/build-protos.sh index dd0e6acaad..0234502943 100755 --- a/weaver/common/protos-js/build-protos.sh +++ b/weaver/common/protos-js/build-protos.sh @@ -13,7 +13,7 @@ grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR - grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/fabric/view_data.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/identity/agent.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/networks/networks.proto -grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto $PROTOSDIR/relay/satp.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto # Typescript Build @@ -23,5 +23,5 @@ protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDD protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/fabric/view_data.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/identity/agent.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/networks/networks.proto -protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto $PROTOSDIR/relay/satp.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index d0240049d6..cbea82e1cb 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -1,17 +1,8 @@ -import ack_pb from '@hyperledger/cacti-weaver-protos-js/common/ack_pb'; -import eventsPb from '@hyperledger/cacti-weaver-protos-js/common/events_pb'; -import events_grpc_pb from '@hyperledger/cacti-weaver-protos-js/relay/events_grpc_pb'; -import queryPb from '@hyperledger/cacti-weaver-protos-js/common/query_pb'; -import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric'; -import { getDriverKeyCert } from "./walletSetup"; -import { DBConnector, DBKeyNotFoundError, LevelDBConnector } from "./dbConnector"; -import { checkIfArraysAreEqual, handlePromise, relayCallback } from "./utils"; -import { registerListenerForEventSubscription, unregisterListenerForEventSubscription } from "./listener"; -import { getNetworkGateway } from "./fabric-code"; -import { Gateway, Network, Contract } from "fabric-network"; -import state_pb from '@hyperledger/cacti-weaver-protos-js/common/state_pb'; +import satp_pb from '@hyperledger/cacti-weaver-protos-js/relay/satp_pb'; +import satp_grpc_pb from '@hyperledger/cacti-weaver-protos-js/relay/satp_grpc_pb'; import driverPb from '@hyperledger/cacti-weaver-protos-js/driver/driver_pb'; import logger from './logger'; +import { credentials } from '@grpc/grpc-js'; import { getNetworkConfig } from './helpers/helpers' import { AssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' @@ -32,12 +23,19 @@ async function performLockHelper( networkName: string ): Promise { + let performLockRequest2 = {}; + performLockRequest2['target-network'] = 'network1'; + performLockRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; + performLockRequest2['timeout-duration'] = '3600'; + performLockRequest2['locker'] = 'alice'; + performLockRequest2['recipient'] = 'bob'; + performLockRequest2['param'] = 'bond01:a03'; // Locker and Recipient - const locker = performLockRequest['locker']; - const recipient = performLockRequest['recipient']; - let hashFn = performLockRequest['hash_fn']; - let hashBase64 = performLockRequest['hashBase64']; + const locker = performLockRequest2['locker']; + const recipient = performLockRequest2['recipient']; + let hashFn = performLockRequest2['hash_fn']; + let hashBase64 = performLockRequest2['hashBase64']; // Hash let hash: HashFunctions.Hash @@ -57,22 +55,22 @@ async function performLockHelper( // Timeout var timeout = 0, timeout2 = 0; const currTime = Math.floor(Date.now() / 1000); - if (performLockRequest['timeout-epoch']) { - let duration = performLockRequest['timeout-epoch'] - currTime - timeout = performLockRequest['timeout-epoch'] - timeout2 = performLockRequest['timeout-epoch'] + duration + if (performLockRequest2['timeout-epoch']) { + let duration = performLockRequest2['timeout-epoch'] - currTime + timeout = performLockRequest2['timeout-epoch'] + timeout2 = performLockRequest2['timeout-epoch'] + duration } - else if (performLockRequest['timeout-duration']) { - timeout = currTime + performLockRequest['timeout-duration'] - timeout2 = currTime + 2 * performLockRequest['timeout-duration'] + else if (performLockRequest2['timeout-duration']) { + timeout = currTime + performLockRequest2['timeout-duration'] + timeout2 = currTime + 2 * performLockRequest2['timeout-duration'] } - const params = performLockRequest['param'].split(':') + const params = performLockRequest2['param'].split(':') + const netConfig = getNetworkConfig(performLockRequest2['target-network']) - const netConfig = getNetworkConfig(performLockRequest['target-network']) if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { console.error( - `Please use a valid --target-network. No valid environment found for ${performLockRequest['target-network']} ` + `Please use a valid --target-network. No valid environment found for ${performLockRequest2['target-network']} ` ) return } @@ -81,12 +79,14 @@ async function performLockHelper( channel: netConfig.channelName, contractName: netConfig.chaincode, connProfilePath: netConfig.connProfilePath, - networkName: performLockRequest['target-network'], + networkName: performLockRequest2['target-network'], mspId: netConfig.mspId, userString: locker }) + logger.info(`network details: ${network}`); const lockerId = await network.wallet.get(locker) + const lockerCert = Buffer.from((lockerId).credentials.certificate).toString('base64') const recipientId = await network.wallet.get(recipient) @@ -94,7 +94,7 @@ async function performLockHelper( var funcToCall, asset - if (performLockRequest['fungible']) { + if (performLockRequest2['fungible']) { funcToCall = AssetManager.createFungibleHTLC asset = 'Fungible Asset' } else { @@ -106,89 +106,69 @@ async function performLockHelper( try { console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) - const res = await funcToCall(network.contract, - params[0], - params[1], - recipientCert, - hash, - timeout, - null) - if (!res.result) { - throw new Error() - } - console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) + // const res = await funcToCall(network.contract, + // params[0], + // params[1], + // recipientCert, + // hash, + // timeout, + // null) + // if (!res.result) { + // throw new Error() + // } + // console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) console.info('Asset Exchange: Lock Complete.') + } catch (error) { - console.error(`Could not Lock ${asset} in ${performLockRequest['target-network']}`) + console.error(`Could not Lock ${asset} in ${performLockRequest2['target-network']}`) } - // await new Promise(f => setTimeout(f, performLockRequest['timeout-duration'] * 1000 + 3000)); + // await new Promise(f => setTimeout(f, performLockRequest2['timeout-duration'] * 1000 + 3000)); await network.gateway.disconnect() - console.log('Gateways disconnected.') - - - // const viewPayload: state_pb.ViewPayload = performLockRequest.getViewPayload(); - // const ctx: eventsPb.ContractTransaction = writeExternalStateMessage.getCtx(); - // const keyCert = await getDriverKeyCert(); - - // const requestId: string = viewPayload.getRequestId(); - // if (!viewPayload.getError()) { - - // let interopArgIndices = [], viewsSerializedBase64 = [], addresses = [], viewContentsBase64 = []; - // const view: state_pb.View = viewPayload.getView(); - - // const result = InteroperableHelper.getResponseDataFromView(view, keyCert.key.toBytes()); - // if (result.contents) { - // viewContentsBase64.push(result.contents); - // } else { - // viewContentsBase64.push([]); - // } - - // interopArgIndices.push(ctx.getReplaceArgIndex()); - // addresses.push(result.viewAddress); - // viewsSerializedBase64.push(Buffer.from(viewPayload.getView().serializeBinary()).toString("base64")); - - // let ccArgsB64 = ctx.getArgsList(); - // let ccArgsStr = []; - // for (const ccArgB64 of ccArgsB64) { - // ccArgsStr.push(Buffer.from(ccArgB64).toString('utf8')); - // } - - // let gateway: Gateway = await getNetworkGateway(networkName); - // const network: Network = await gateway.getNetwork(ctx.getLedgerId()); - // const interopContract: Contract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); - - // const endorsingOrgs = ctx.getMembersList(); - // const invokeObject = { - // channel: ctx.getLedgerId(), - // ccFunc: ctx.getFunc(), - // ccArgs: ccArgsStr, - // contractName: ctx.getContractId() - // } - // logger.info(`writing external state to contract: ${ctx.getContractId()} with function: ${ctx.getFunc()}, and args: ${invokeObject.ccArgs} on channel: ${ctx.getLedgerId()}`); - - // const [ response, responseError ] = await handlePromise(InteroperableHelper.submitTransactionWithRemoteViews( - // interopContract, - // invokeObject, - // interopArgIndices, - // addresses, - // viewsSerializedBase64, - // viewContentsBase64, - // endorsingOrgs - // )); - // if (responseError) { - // logger.error(`Failed writing to the ledger with error: ${responseError}`); - // gateway.disconnect(); - // throw responseError; - // } - // logger.debug(`write successful`); - // gateway.disconnect(); - // } else { - // const errorString: string = `erroneous viewPayload identified in WriteExternalState processing`; - // logger.error(`error viewPayload.getError(): ${JSON.stringify(viewPayload.getError())}`); - // throw new Error(errorString); - // } + logger.info('Gateways disconnected.') + + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(performLockRequest.getSessionId()); + request.setStatus("Locked"); + client.sendAssetStatus(request, relayCallback); +} + +function getRelayClientForAssetStatusResponse() { + let client: satp_grpc_pb.SATPClient; + if (process.env.RELAY_TLS === 'true') { + if (!process.env.RELAY_TLSCA_CERT_PATH || process.env.RELAY_TLSCA_CERT_PATH == "") { + client = new satp_grpc_pb.SATPClient( + process.env.RELAY_ENDPOINT, + credentials.createSsl() + ); + } else { + if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { + throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); + } + const rootCert = fs.readFileSync(process.env.RELAY_TLSCA_CERT_PATH); + client = new satp_grpc_pb.SATPClient( + process.env.RELAY_ENDPOINT, + credentials.createSsl(rootCert) + ); + } + } else { + client = new satp_grpc_pb.SATPClient( + process.env.RELAY_ENDPOINT, + credentials.createInsecure() + ); + } + return client; +} + +// handle callback +function relayCallback(err: any, response: any) { + if (response) { + logger.info(`Relay Callback Response: ${JSON.stringify(response.toObject())}`); + } else if (err) { + logger.error(`Relay Callback Error: ${err}`); + } } export { From c1fbb4647ef1a244c0021ca1a8019f50f4437cd3 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 29 Aug 2023 08:54:03 +0100 Subject: [PATCH 23/59] Colorful log to show different stages and steps --- .../core/drivers/fabric-driver/server/satp.ts | 30 +-- weaver/core/relay/Cargo.lock | 66 ++++- weaver/core/relay/Cargo.toml | 1 + weaver/core/relay/src/services/helpers.rs | 237 ++++++++++++------ .../core/relay/src/services/satp_service.rs | 27 ++ 5 files changed, 263 insertions(+), 98 deletions(-) diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index cbea82e1cb..9509ba59de 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -26,10 +26,10 @@ async function performLockHelper( let performLockRequest2 = {}; performLockRequest2['target-network'] = 'network1'; performLockRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; - performLockRequest2['timeout-duration'] = '3600'; + performLockRequest2['timeout-duration'] = parseInt('3600'); performLockRequest2['locker'] = 'alice'; performLockRequest2['recipient'] = 'bob'; - performLockRequest2['param'] = 'bond01:a03'; + performLockRequest2['param'] = 'bond01:a05'; // Locker and Recipient const locker = performLockRequest2['locker']; @@ -84,11 +84,8 @@ async function performLockHelper( userString: locker }) - logger.info(`network details: ${network}`); const lockerId = await network.wallet.get(locker) - const lockerCert = Buffer.from((lockerId).credentials.certificate).toString('base64') - const recipientId = await network.wallet.get(recipient) const recipientCert = Buffer.from((recipientId).credentials.certificate).toString('base64') @@ -103,20 +100,19 @@ async function performLockHelper( } console.info(`Asset Exchange: Lock ${asset}:\n`); - try { console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) - // const res = await funcToCall(network.contract, - // params[0], - // params[1], - // recipientCert, - // hash, - // timeout, - // null) - // if (!res.result) { - // throw new Error() - // } - // console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) + const res = await funcToCall(network.contract, + params[0], + params[1], + recipientCert, + hash, + timeout, + null) + if (!res.result) { + throw new Error() + } + console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) console.info('Asset Exchange: Lock Complete.') } catch (error) { diff --git a/weaver/core/relay/Cargo.lock b/weaver/core/relay/Cargo.lock index e0873a2b4c..de08f8c158 100644 --- a/weaver/core/relay/Cargo.lock +++ b/weaver/core/relay/Cargo.lock @@ -85,7 +85,7 @@ checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes", "futures-util", "http", @@ -170,6 +170,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "bumpalo" version = "3.13.0" @@ -209,6 +215,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "colored" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +dependencies = [ + "is-terminal", + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "config" version = "0.11.0" @@ -644,6 +661,17 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix 0.38.9", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -681,7 +709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ "arrayvec", - "bitflags", + "bitflags 1.3.2", "cfg-if", "ryu", "static_assertions", @@ -705,6 +733,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" + [[package]] name = "listenfd" version = "1.0.1" @@ -863,7 +897,7 @@ version = "0.10.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "foreign-types", "libc", @@ -1104,7 +1138,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1113,7 +1147,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1140,6 +1174,7 @@ dependencies = [ "base64 0.20.0", "bincode", "cacti_weaver_protos_rs", + "colored", "config", "futures", "listenfd", @@ -1223,11 +1258,24 @@ version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.5", "windows-sys 0.48.0", ] @@ -1295,7 +1343,7 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -1464,7 +1512,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix", + "rustix 0.37.20", "windows-sys 0.48.0", ] diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index 123e42eec4..43fa28f188 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -39,6 +39,7 @@ reqwest = { version = "0.11.16", features = ["json"] } serde_json = "1.0.95" # cacti_weaver_protos_rs = "2.0.0-alpha.1" cacti_weaver_protos_rs = { path = "../../common/protos-rs/pkg" } +colored = {version="2.0.4"} [build-dependencies] tonic-build = "0.8.4" diff --git a/weaver/core/relay/src/services/helpers.rs b/weaver/core/relay/src/services/helpers.rs index cb1825e0d5..ce6aecb9ca 100644 --- a/weaver/core/relay/src/services/helpers.rs +++ b/weaver/core/relay/src/services/helpers.rs @@ -1,17 +1,18 @@ -use weaverpb::common::ack::{ack}; +use colored::Colorize; +use weaverpb::common::ack::ack; +use weaverpb::common::events::{event_subscription_state, EventSubscriptionState}; +use weaverpb::common::events::{EventPublication, EventState, EventStates, EventSubscription}; use weaverpb::common::query::Query; use weaverpb::common::state::{request_state, RequestState}; -use weaverpb::common::events::{event_subscription_state, EventSubscriptionState}; -use weaverpb::common::events::{EventSubscription, EventStates, EventState, EventPublication}; use weaverpb::driver::driver::driver_communication_client::DriverCommunicationClient; use crate::db::Database; -use crate::services::types::{Driver, Network}; use crate::error::Error; +use crate::services::types::{Driver, Network}; use config; -use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use std::fs; +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; // Locally scoped function to update request status in db. This function is // called for the first time after an Ack is received from the remote relay. @@ -26,11 +27,20 @@ pub fn update_event_subscription_status( db_open_retry_backoff_msec: u32, message: String, ) { - let driver_error_constants = fs::read_to_string("./driver/driver-error-constants.json").expect("Unable to read file: ./driver/driver-error-constants.json"); + let driver_error_constants = fs::read_to_string("./driver/driver-error-constants.json") + .expect("Unable to read file: ./driver/driver-error-constants.json"); let driver_error_constants_json: serde_json::Value = serde_json::from_str(&driver_error_constants).expect("JSON was not well-formatted"); - let driver_sub_exists_error = driver_error_constants_json.get("SUB_EXISTS").unwrap().as_str().unwrap(); - let driver_sub_exists_error_without_args = *(driver_sub_exists_error.split("{0}").collect::>().first().unwrap()); + let driver_sub_exists_error = driver_error_constants_json + .get("SUB_EXISTS") + .unwrap() + .as_str() + .unwrap(); + let driver_sub_exists_error_without_args = *(driver_sub_exists_error + .split("{0}") + .collect::>() + .first() + .unwrap()); let db = Database { db_path: curr_db_path, @@ -49,42 +59,52 @@ pub fn update_event_subscription_status( target = EventSubscriptionState { status: event_subscription_state::Status::UnsubscribePending as i32, request_id: curr_request_id.clone(), - publishing_request_id: fetched_event_sub_state.publishing_request_id.to_string(), + publishing_request_id: fetched_event_sub_state + .publishing_request_id + .to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher, - event_publication_specs: fetched_event_sub_state.event_publication_specs + event_publication_specs: fetched_event_sub_state + .event_publication_specs, }; - }, + } event_subscription_state::Status::UnsubscribePending => { target = EventSubscriptionState { status: event_subscription_state::Status::Unsubscribed as i32, request_id: curr_request_id.clone(), - publishing_request_id: fetched_event_sub_state.publishing_request_id.to_string(), + publishing_request_id: fetched_event_sub_state + .publishing_request_id + .to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher, - event_publication_specs: fetched_event_sub_state.event_publication_specs + event_publication_specs: fetched_event_sub_state + .event_publication_specs, }; - }, - event_subscription_state::Status::SubscribePendingAck => { + } + event_subscription_state::Status::SubscribePendingAck => { target = EventSubscriptionState { status: event_subscription_state::Status::SubscribePending as i32, request_id: curr_request_id.clone(), publishing_request_id: "".to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, - event_subscription_state::Status::SubscribePending => { + } + event_subscription_state::Status::SubscribePending => { target = EventSubscriptionState { status: event_subscription_state::Status::Subscribed as i32, request_id: curr_request_id.clone(), publishing_request_id: curr_request_id.clone(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, + } _ => { target = EventSubscriptionState { status: event_subscription_state::Status::Error as i32, @@ -92,9 +112,11 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: "Status is not supported or is invalid".to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, + } }, None => { target = EventSubscriptionState { @@ -103,41 +125,61 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: "No event subscription status set in database".to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, + } } } else { match message.find(driver_sub_exists_error_without_args) { Some(_index) => { - let old_request_id = *(message.split(driver_sub_exists_error_without_args).collect::>().last().unwrap()); + let old_request_id = *(message + .split(driver_sub_exists_error_without_args) + .collect::>() + .last() + .unwrap()); println!("Adding event publication spec to existing EventSubscriptionState. Extracted request id from message: {}", old_request_id.to_string()); - let old_event_sub_key = get_event_subscription_key(old_request_id.to_string()); - let mut existing_event_sub_state = db.get::(old_event_sub_key.to_string()) - .expect(&format!("No EventSubscriptionState found in DB for request_id provided {}", old_request_id.to_string())); - - let new_event_pub_spec = fetched_event_sub_state.event_publication_specs.first().unwrap(); + let old_event_sub_key = + get_event_subscription_key(old_request_id.to_string()); + let mut existing_event_sub_state = db + .get::(old_event_sub_key.to_string()) + .expect(&format!( + "No EventSubscriptionState found in DB for request_id provided {}", + old_request_id.to_string() + )); + + let new_event_pub_spec = fetched_event_sub_state + .event_publication_specs + .first() + .unwrap(); let mut unique_pub_spec_flag = true; - for event_pub_spec in existing_event_sub_state.event_publication_specs.iter() { + for event_pub_spec in + existing_event_sub_state.event_publication_specs.iter() + { if *new_event_pub_spec == *event_pub_spec { unique_pub_spec_flag = false; break; } } if unique_pub_spec_flag { - existing_event_sub_state.event_publication_specs.push((*new_event_pub_spec).clone()); + existing_event_sub_state + .event_publication_specs + .push((*new_event_pub_spec).clone()); let updated_event_sub_state = EventSubscriptionState { status: event_subscription_state::Status::Subscribed as i32, request_id: old_request_id.to_string(), publishing_request_id: old_request_id.to_string(), message: existing_event_sub_state.message.to_string(), event_matcher: existing_event_sub_state.event_matcher.clone(), - event_publication_specs: existing_event_sub_state.event_publication_specs.clone(), + event_publication_specs: existing_event_sub_state + .event_publication_specs + .clone(), }; db.set(&old_event_sub_key.to_string(), &updated_event_sub_state) .expect("Failed to insert into DB"); - + target = EventSubscriptionState { status: event_subscription_state::Status::DuplicateQuerySubscribed as i32, request_id: curr_request_id.clone(), @@ -153,10 +195,12 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), } }; - }, + } None => { target = EventSubscriptionState { status: event_subscription_state::Status::Error as i32, @@ -164,28 +208,31 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; } } } - + // Panic if this fails, atm the panic is just logged by the tokio runtime db.set(&event_sub_key.to_string(), &target) .expect("Failed to insert into DB"); println!("Successfully written EventSubscriptionState to database"); - println!("{:?}\n", db.get::(event_sub_key.to_string()).unwrap()) - }, + println!( + "{:?}\n", + db.get::(event_sub_key.to_string()) + .unwrap() + ) + } Err(e) => { println!("EventSubscription Request not found. Error: {:?}", e); - }, + } } } -pub fn get_driver( - network_id: String, - conf: config::Config, -) -> Result { +pub fn get_driver(network_id: String, conf: config::Config) -> Result { // get the driver type from the networks map let networks_table = conf .get_table("networks") @@ -235,7 +282,8 @@ pub async fn get_driver_client( .ca_certificate(ca) .domain_name(hostname); - let channel = Channel::from_shared(driver_address).unwrap() + let channel = Channel::from_shared(driver_address) + .unwrap() .tls_config(tls)? .connect() .await @@ -245,10 +293,9 @@ pub async fn get_driver_client( } else { client = DriverCommunicationClient::connect(driver_address).await?; } - return Ok(client) + return Ok(client); } - pub async fn driver_sign_subscription_helper( event_subscription: EventSubscription, request_id: String, @@ -259,7 +306,10 @@ pub async fn driver_sign_subscription_helper( match result { Ok(driver_info) => { let client = get_driver_client(driver_info).await?; - println!("Sending Sign EventSubscription Request to driver: {:?}", event_subscription.clone()); + println!( + "Sending Sign EventSubscription Request to driver: {:?}", + event_subscription.clone() + ); let signed_query = client .clone() .request_signed_event_subscription_query(event_subscription) @@ -267,10 +317,13 @@ pub async fn driver_sign_subscription_helper( .into_inner(); if signed_query.clone().request_id.to_string() == request_id.to_string() { println!("Signed Query Response from driver={:?}\n", signed_query); - return Ok(signed_query) + return Ok(signed_query); } - Err(Error::Simple(format!("Error while requesting signature from driver: {:?}", signed_query))) - }, + Err(Error::Simple(format!( + "Error while requesting signature from driver: {:?}", + signed_query + ))) + } Err(e) => Err(e), } } @@ -307,8 +360,7 @@ pub fn update_event_state( message: message.to_string(), }; updated_event_states.push(new_event_state); - } - else { + } else { updated_event_states.push(fetched_event_state); } } @@ -316,17 +368,18 @@ pub fn update_event_state( db.set(&event_publish_key.to_string(), &updated_event_states) .expect("Failed to insert into DB"); println!("Successfully updated EventStates in database"); - }, + } Err(e) => { println!("EventStates not found. Error: {:?}", e); - }, + } } } pub fn try_mark_request_state_deleted(state: RequestState, request_id: String, db: Database) { let state_status = request_state::Status::from_i32(state.clone().status).expect("No Status"); - if state_status == request_state::Status::Error || - state_status == request_state::Status::Completed { + if state_status == request_state::Status::Error + || state_status == request_state::Status::Completed + { let deleted_request_state = RequestState { status: request_state::Status::Deleted as i32, request_id: request_id.to_string(), @@ -337,7 +390,12 @@ pub fn try_mark_request_state_deleted(state: RequestState, request_id: String, d } } -pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: String, event_publish_key: String, db: Database) { +pub fn mark_event_states_deleted( + fetched_event_states: EventStates, + request_id: String, + event_publish_key: String, + db: Database, +) { let mut updated_event_states: Vec = Vec::new(); for fetched_event_state in fetched_event_states.states { let deleted_request_state = RequestState { @@ -352,7 +410,7 @@ pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: }; updated_event_states.push(deleted_event_state); } - + db.set(&event_publish_key.to_string(), &updated_event_states) .expect("EventState Delete: Failed to insert into DB"); } @@ -377,11 +435,15 @@ pub fn delete_event_pub_spec( db_open_retry_backoff_msec: db_open_retry_backoff_msec, }; let mut event_sub_key = get_event_subscription_key(request_id.to_string()); - let mut event_sub_state = db.get::(event_sub_key.to_string()) - .expect(&format!("No EventSubscriptionState found in DB for request_id provided {}", request_id.to_string())); - + let mut event_sub_state = db + .get::(event_sub_key.to_string()) + .expect(&format!( + "No EventSubscriptionState found in DB for request_id provided {}", + request_id.to_string() + )); + let mut del_event_pub_spec = event_pub_spec; - + if event_sub_state.status == event_subscription_state::Status::DuplicateQuerySubscribed as i32 { let updated_state = EventSubscriptionState { status: event_subscription_state::Status::Unsubscribed as i32, @@ -389,18 +451,30 @@ pub fn delete_event_pub_spec( publishing_request_id: event_sub_state.publishing_request_id.to_string(), message: "Unsubscription successful".to_string(), event_matcher: event_sub_state.event_matcher, - event_publication_specs: event_sub_state.event_publication_specs + event_publication_specs: event_sub_state.event_publication_specs, }; db.set(&event_sub_key.to_string(), &updated_state) .expect("Failed to insert into DB"); - del_event_pub_spec = updated_state.clone().event_publication_specs.first().unwrap().clone(); - println!("Removed EventSubscriptionState from database: {:?}", updated_state); + del_event_pub_spec = updated_state + .clone() + .event_publication_specs + .first() + .unwrap() + .clone(); + println!( + "Removed EventSubscriptionState from database: {:?}", + updated_state + ); event_sub_key = get_event_subscription_key(updated_state.publishing_request_id.to_string()); - event_sub_state = db.get::(event_sub_key.to_string()) - .expect(&format!("No EventSubscriptionState found in DB for request_id provided {}", updated_state.publishing_request_id.to_string())); + event_sub_state = db + .get::(event_sub_key.to_string()) + .expect(&format!( + "No EventSubscriptionState found in DB for request_id provided {}", + updated_state.publishing_request_id.to_string() + )); } - + let mut flag = true; for (i, curr_event_pub_spec) in event_sub_state.event_publication_specs.iter().enumerate() { if *curr_event_pub_spec == del_event_pub_spec { @@ -418,13 +492,32 @@ pub fn delete_event_pub_spec( db.set(&event_sub_key.to_string(), &event_sub_state) .expect("Failed to insert into DB"); println!("Successfully deleted Event Publication from existing EventSubscriptionState from DB"); - + return 0; } pub fn get_event_subscription_key(request_id: String) -> String { return format!("event_sub_{}", request_id); } + pub fn get_event_publication_key(request_id: String) -> String { return format!("event_pub_{}", request_id); -} \ No newline at end of file +} + +pub fn println_stage_heading(stage_id: String) { + println!( + "{} {} {}", + "\n --------- Stage".yellow().bold(), + stage_id.yellow().bold(), + "started --------- \n".yellow().bold() + ); +} + +pub fn println_step_heading(step_id: String) { + println!( + "{} {} {}", + "\n --------- Step".bright_cyan().bold(), + step_id.bright_cyan().bold(), + " --------- \n".bright_cyan().bold() + ); +} diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index b9bf229eb9..14e970b4a5 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -12,6 +12,7 @@ use weaverpb::relay::satp::{ // Internal modules use crate::error::Error; use crate::relay_proto::parse_address; +use crate::services::helpers::{println_stage_heading, println_step_heading}; use crate::services::satp_helper::{ create_ack_error_message, create_perform_lock_request, get_request_id_from_transfer_proposal_receipt, log_request_in_local_satp_db, @@ -55,6 +56,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_stage_heading("1".to_string()); + println_step_heading("1.1".to_string()); println!( "Got a TransferProposalClaimsRequest from {:?} - {:?}", request.remote_addr(), @@ -108,6 +111,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("1.2".to_string()); println!( "Got an ack transfer proposal receipt request from {:?} - {:?}", request.remote_addr(), @@ -169,6 +173,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("1.3".to_string()); println!( "Got a TransferCommenceRequest from {:?} - {:?}", request.remote_addr(), @@ -214,6 +219,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("1.4".to_string()); println!( "Got an ack commence request from {:?} - {:?}", request.remote_addr(), @@ -312,6 +318,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("2.2".to_string()); println!( "Got a LockAssertionRequest from {:?} - {:?}", request.remote_addr(), @@ -354,6 +361,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("2.4".to_string()); println!( "Got an lock assertion receipt request from {:?} - {:?}", request.remote_addr(), @@ -408,6 +416,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("3.1".to_string()); println!( "Got commit prepare request from {:?} - {:?}", request.remote_addr(), @@ -456,6 +465,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("3.3".to_string()); println!( "Got commit ready request from {:?} - {:?}", request.remote_addr(), @@ -503,6 +513,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("3.5".to_string()); println!( "Got commit final assertion request from {:?} - {:?}", request.remote_addr(), @@ -557,6 +568,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("3.7".to_string()); println!( "Got commit final assertion request from {:?} - {:?}", request.remote_addr(), @@ -608,6 +620,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("3.9".to_string()); println!( "Got commit final assertion request from {:?} - {:?}", request.remote_addr(), @@ -813,23 +826,27 @@ pub fn process_send_asset_status_request( let status = send_asset_status_request.status.as_str(); match status { "Locked" => { + println_step_heading("2.1B".to_string()); println!("Received asset status as Locked. Sending the lock assertion request"); let lock_assertion_request = create_lock_assertion_request(send_asset_status_request); result = send_lock_assertion_request(lock_assertion_request, conf) } "Created" => { + println_step_heading("3.2B".to_string()); println!("Received asset status as Created. Sending the commit ready request"); let commit_ready_request = create_commit_ready_request(send_asset_status_request); result = send_commit_ready_request(commit_ready_request, conf); } "Extinguished" => { + println_step_heading("3.4B".to_string()); println!("Received asset status as Extinguished. Sending the commit final assertion request"); let commit_final_assertion_request = create_commit_final_assertion_request(send_asset_status_request); result = send_commit_final_assertion_request(commit_final_assertion_request, conf) } "Finalized" => { + println_step_heading("3.6B".to_string()); println!( "Received asset status as Finalized. Sending the ack final receipt request" ); @@ -1184,6 +1201,8 @@ fn send_lock_assertion_broadcast_request( lock_assertion_request: LockAssertionRequest, conf: config::Config, ) -> Result { + println_step_heading("2.3".to_string()); + let request_id = &lock_assertion_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); let (use_tls, tlsca_cert_path) = @@ -1209,6 +1228,9 @@ fn send_perform_lock_request( perform_lock_request: PerformLockRequest, conf: config::Config, ) -> Result { + println_stage_heading("2".to_string()); + println_step_heading("2.1A".to_string()); + let request_id = &perform_lock_request.session_id.to_string(); let driver_address = get_driver_address_from_perform_lock(perform_lock_request.clone()); let parsed_address = parse_address(driver_address)?; @@ -1240,6 +1262,7 @@ fn send_commit_prepare_request( commit_prepare_request: CommitPrepareRequest, conf: config::Config, ) -> Result { + println_stage_heading("3".to_string()); let request_id = &commit_prepare_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); let (use_tls, tlsca_cert_path) = @@ -1293,6 +1316,7 @@ fn send_create_asset_request( conf: config::Config, ) -> Result { // TODO + println_step_heading("3.2A".to_string()); let request_id = &commit_prepare_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); let (use_tls, tlsca_cert_path) = @@ -1320,6 +1344,7 @@ fn send_extinguish_request( conf: config::Config, ) -> Result { // TODO + println_step_heading("3.4A".to_string()); let request_id = &commit_ready_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_commit_ready(commit_ready_request.clone()); let (use_tls, tlsca_cert_path) = @@ -1375,6 +1400,7 @@ fn send_ack_final_receipt_request( conf: config::Config, ) -> Result { // TODO + println_step_heading("3.8".to_string()); let request_id = &ack_final_receipt_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); @@ -1403,6 +1429,7 @@ fn send_assign_asset_request( conf: config::Config, ) -> Result { // TODO + println_step_heading("3.6A".to_string()); let request_id = &commit_final_assertion_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_commit_final_assertion(commit_final_assertion_request.clone()); From ae0aa5a3fc375b9717aae3d82c1e1030036dd439 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Thu, 31 Aug 2023 08:38:47 +0100 Subject: [PATCH 24/59] Initial commit for create-asset, extinguish, and assign-asset --- .../pkg/src/generated/driver.driver.rs | 242 +++++++++++++++++- weaver/common/protos/driver/driver.proto | 26 +- .../core/drivers/fabric-driver/server/satp.ts | 66 ++++- .../drivers/fabric-driver/server/server.ts | 68 ++++- weaver/core/relay/src/services/satp_helper.rs | 211 ++++++++++++--- .../core/relay/src/services/satp_service.rs | 171 ++++++++----- 6 files changed, 656 insertions(+), 128 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs index 15de731bd4..1a89c27a54 100644 --- a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs +++ b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs @@ -15,6 +15,27 @@ pub struct PerformLockRequest { #[prost(string, tag = "1")] pub session_id: ::prost::alloc::string::String, } +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateAssetRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExtinguishRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AssignAssetRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} /// Generated client implementations. pub mod driver_communication_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] @@ -186,7 +207,7 @@ pub mod driver_communication_client { ); self.inner.unary(request.into_request(), path, codec).await } - /// As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + /// As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver /// to lock a specific asset pub async fn perform_lock( &mut self, @@ -210,6 +231,78 @@ pub mod driver_communication_client { ); self.inner.unary(request.into_request(), path, codec).await } + /// As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + /// to create a specific asset + pub async fn create_asset( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/CreateAsset", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + /// to extinguish a specific asset + pub async fn extinguish( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/Extinguish", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + /// to assign a specific asset + pub async fn assign_asset( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/AssignAsset", + ); + self.inner.unary(request.into_request(), path, codec).await + } } } /// Generated server implementations. @@ -261,7 +354,7 @@ pub mod driver_communication_server { tonic::Response, tonic::Status, >; - /// As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + /// As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver /// to lock a specific asset async fn perform_lock( &self, @@ -270,6 +363,33 @@ pub mod driver_communication_server { tonic::Response, tonic::Status, >; + /// As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + /// to create a specific asset + async fn create_asset( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + /// to extinguish a specific asset + async fn extinguish( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + /// to assign a specific asset + async fn assign_asset( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct DriverCommunicationServer { @@ -545,6 +665,124 @@ pub mod driver_communication_server { }; Box::pin(fut) } + "/driver.driver.DriverCommunication/CreateAsset" => { + #[allow(non_camel_case_types)] + struct CreateAssetSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for CreateAssetSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).create_asset(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CreateAssetSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/driver.driver.DriverCommunication/Extinguish" => { + #[allow(non_camel_case_types)] + struct ExtinguishSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for ExtinguishSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).extinguish(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = ExtinguishSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/driver.driver.DriverCommunication/AssignAsset" => { + #[allow(non_camel_case_types)] + struct AssignAssetSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for AssignAssetSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).assign_asset(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = AssignAssetSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( diff --git a/weaver/common/protos/driver/driver.proto b/weaver/common/protos/driver/driver.proto index db1a1112b9..c608f4f597 100644 --- a/weaver/common/protos/driver/driver.proto +++ b/weaver/common/protos/driver/driver.proto @@ -20,6 +20,18 @@ message PerformLockRequest { string session_id = 1; } +message CreateAssetRequest { + string session_id = 1; +} + +message ExtinguishRequest { + string session_id = 1; +} + +message AssignAssetRequest { + string session_id = 1; +} + service DriverCommunication { // Data Sharing // the remote relay sends a RequestDriverState request to its driver with a @@ -39,7 +51,19 @@ service DriverCommunication { // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger rpc WriteExternalState(WriteExternalStateMessage) returns (common.ack.Ack) {} - // As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + // As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver // to lock a specific asset rpc PerformLock(PerformLockRequest) returns (common.ack.Ack) {} + + // As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + // to create a specific asset + rpc CreateAsset(CreateAssetRequest) returns (common.ack.Ack) {} + + // As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + // to extinguish a specific asset + rpc Extinguish(ExtinguishRequest) returns (common.ack.Ack) {} + + // As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + // to assign a specific asset + rpc AssignAsset(AssignAssetRequest) returns (common.ack.Ack) {} } \ No newline at end of file diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index 9509ba59de..fea151a0c3 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -102,17 +102,17 @@ async function performLockHelper( console.info(`Asset Exchange: Lock ${asset}:\n`); try { console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) - const res = await funcToCall(network.contract, - params[0], - params[1], - recipientCert, - hash, - timeout, - null) - if (!res.result) { - throw new Error() - } - console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) + // const res = await funcToCall(network.contract, + // params[0], + // params[1], + // recipientCert, + // hash, + // timeout, + // null) + // if (!res.result) { + // throw new Error() + // } + // console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) console.info('Asset Exchange: Lock Complete.') } catch (error) { @@ -131,6 +131,45 @@ async function performLockHelper( client.sendAssetStatus(request, relayCallback); } +async function createAssetHelper( + createAssetRequest: driverPb.CreateAssetRequest, + networkName: string +): Promise { + + // TODO + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(createAssetRequest.getSessionId()); + request.setStatus("Created"); + client.sendAssetStatus(request, relayCallback); +} + +async function extinguishHelper( + extinguishRequest: driverPb.ExtinguishRequest, + networkName: string +): Promise { + + // TODO + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(extinguishRequest.getSessionId()); + request.setStatus("Extinguished"); + client.sendAssetStatus(request, relayCallback); +} + +async function assignAssetHelper( + assignAssetRequest: driverPb.AssignAssetRequest, + networkName: string +): Promise { + + // TODO + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(assignAssetRequest.getSessionId()); + request.setStatus("Finalized"); + client.sendAssetStatus(request, relayCallback); +} + function getRelayClientForAssetStatusResponse() { let client: satp_grpc_pb.SATPClient; if (process.env.RELAY_TLS === 'true') { @@ -168,5 +207,8 @@ function relayCallback(err: any, response: any) { } export { - performLockHelper + performLockHelper, + createAssetHelper, + extinguishHelper, + assignAssetHelper } diff --git a/weaver/core/drivers/fabric-driver/server/server.ts b/weaver/core/drivers/fabric-driver/server/server.ts index d31c7805ff..427307e149 100644 --- a/weaver/core/drivers/fabric-driver/server/server.ts +++ b/weaver/core/drivers/fabric-driver/server/server.ts @@ -19,7 +19,7 @@ import 'dotenv/config'; import { loadEventSubscriptionsFromStorage, monitorBlockForMissedEvents } from './listener' import { walletSetup } from './walletSetup'; import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery, writeExternalStateHelper } from "./events" -import { performLockHelper } from "./satp" +import { performLockHelper, createAssetHelper, extinguishHelper, assignAssetHelper } from "./satp" import * as path from 'path'; import { handlePromise, relayCallback, getRelayClientForQueryResponse, getRelayClientForEventSubscription, delay } from './utils'; import { dbConnectionTest, eventSubscriptionTest } from "./tests" @@ -240,7 +240,70 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { performLockHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { const ack_response = new ack_pb.Ack(); ack_response.setRequestId(requestId); - ack_response.setMessage('Successfully written to the ledger'); + ack_response.setMessage('Successfully locked the asset'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, + createAsset: (call: { request: driverPb.CreateAssetRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + createAssetHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully created the asset'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, + extinguish: (call: { request: driverPb.ExtinguishRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + extinguishHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully extinguished the asset'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, + assignAsset: (call: { request: driverPb.AssignAssetRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + assignAssetHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully assigned the asset'); ack_response.setStatus(ack_pb.Ack.STATUS.OK); // gRPC response. logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); @@ -255,6 +318,7 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { callback(null, ack_err_response); }); }, + }); // Prepares required crypto material for communication with the fabric network diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 9894ca8f69..61c13bf146 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -6,7 +6,9 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use tonic::Response; use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::state::{request_state, RequestState}; -use weaverpb::driver::driver::PerformLockRequest; +use weaverpb::driver::driver::{ + AssignAssetRequest, CreateAssetRequest, ExtinguishRequest, PerformLockRequest, +}; use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ @@ -277,24 +279,28 @@ pub fn spawn_send_commit_prepare_request( } pub fn spawn_send_create_asset_request( - commit_prepare_request: CommitPrepareRequest, - relay_host: String, - relay_port: String, - use_tls: bool, - tlsca_cert_path: String, - conf: Config, + driver_info: Driver, + create_asset_request: CreateAssetRequest, ) { tokio::spawn(async move { - let request_id = commit_prepare_request.session_id.to_string(); + let request_id = create_asset_request.session_id.to_string(); println!( - "Creating the asset corresponding to the commit prepare request {:?}", + "Creating the asset corresponding to the create asset request {:?}", request_id ); - // TODO - // Creating the asset in the target network - // Subscribe to the status event - // Once the message is broadcast, call the call_commit_ready endpoint - // log the results + + // TODO: pass the required info to lock the relevant asset + // Call the driver to lock the asset + let result = call_create_asset(driver_info, create_asset_request).await; + match result { + Ok(_) => { + println!("Create asset request sent to driver\n") + } + Err(e) => { + println!("Error sending create asset request to driver: {:?}\n", e); + // TODO: what to do in this case? + } + } }); } @@ -325,23 +331,28 @@ pub fn spawn_send_commit_ready_request( } pub fn spawn_send_assign_asset_request( - commit_final_assertion_request: CommitFinalAssertionRequest, - relay_host: String, - relay_port: String, - use_tls: bool, - tlsca_cert_path: String, - conf: Config, + driver_info: Driver, + assign_asset_request: AssignAssetRequest, ) { tokio::spawn(async move { - let request_id = commit_final_assertion_request.session_id.to_string(); + let request_id = assign_asset_request.session_id.to_string(); println!( - "Assigning the asset corresponding to the commit final assertion request {:?}", + "Assigning the asset corresponding to the assign asset request {:?}", request_id ); - // TODO - // Assigning the asset in the target network - // Once the asset is assigned, call the call_ack_final_receipt endpoint - // log the results + + // TODO: pass the required info to assign the relevant asset + // Call the driver to assign the asset + let result = call_assign_asset(driver_info, assign_asset_request).await; + match result { + Ok(_) => { + println!("Assign asset request sent to driver\n") + } + Err(e) => { + println!("Error sending assign asset request to driver: {:?}\n", e); + // TODO: what to do in this case? + } + } }); } @@ -408,24 +419,29 @@ pub fn spawn_send_ack_final_receipt_broadcast_request( }); } -pub fn spawn_send_extinguish_request( - commit_ready_request: CommitReadyRequest, - relay_host: String, - relay_port: String, - use_tls: bool, - tlsca_cert_path: String, - conf: Config, -) { +pub fn spawn_send_extinguish_request(driver_info: Driver, extinguish_request: ExtinguishRequest) { tokio::spawn(async move { - let request_id = commit_ready_request.session_id.to_string(); + let request_id = extinguish_request.session_id.to_string(); println!( - "Extinguishing the asset corresponding to the commit final assertion request {:?}", + "Extinguishing the asset corresponding to the extinguish request {:?}", request_id ); - // TODO - // Assigning the asset in the target network - // Once the asset is assigned, call the call_ack_final_receipt endpoint - // log the results + + // TODO: pass the required info to lock the relevant asset + // Call the driver to lock the asset + let result = call_extinguish(driver_info, extinguish_request).await; + match result { + Ok(_) => { + println!("Extinguishing asset request sent to driver\n") + } + Err(e) => { + println!( + "Error sending extinguishing asset request to driver: {:?}\n", + e + ); + // TODO: what to do in this case? + } + } }); } @@ -482,6 +498,78 @@ async fn call_perform_lock( } } +async fn call_create_asset( + driver_info: Driver, + create_asset_request: CreateAssetRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to create the asset"); + let ack = client + .clone() + .create_asset(create_asset_request) + .await? + .into_inner(); + println!("Response ACK from driver to create the asset {:?}\n", ack); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + +async fn call_extinguish( + driver_info: Driver, + extinguish_request: ExtinguishRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to extinguish the asset"); + let ack = client + .clone() + .extinguish(extinguish_request) + .await? + .into_inner(); + println!( + "Response ACK from driver to extinguish the asset {:?}\n", + ack + ); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + +async fn call_assign_asset( + driver_info: Driver, + assign_asset_request: AssignAssetRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to assign the asset"); + let ack = client + .clone() + .assign_asset(assign_asset_request) + .await? + .into_inner(); + println!("Response ACK from driver to assign the asset {:?}\n", ack); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + // Call the transfer_commence endpoint on the receiver gateway pub async fn call_transfer_commence( relay_host: String, @@ -946,6 +1034,34 @@ pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> return perform_lock_request; } +pub fn create_create_asset_request( + commit_prepare_request: CommitPrepareRequest, +) -> CreateAssetRequest { + // TODO: remove hard coded values + let create_asset_request = CreateAssetRequest { + session_id: "session_id1".to_string(), + }; + return create_asset_request; +} + +pub fn create_extinguish_request(commit_ready_request: CommitReadyRequest) -> ExtinguishRequest { + // TODO: remove hard coded values + let extinguish_request = ExtinguishRequest { + session_id: "session_id1".to_string(), + }; + return extinguish_request; +} + +pub fn create_assign_asset_request( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> AssignAssetRequest { + // TODO: remove hard coded values + let assign_asset_request = AssignAssetRequest { + session_id: "session_id1".to_string(), + }; + return assign_asset_request; +} + pub fn generate_commit_final_assertion_request( commit_ready_request: CommitReadyRequest, ) -> CommitFinalAssertionRequest { @@ -1171,6 +1287,21 @@ pub fn get_driver_address_from_perform_lock(perform_lock_request: PerformLockReq return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); } +pub fn get_driver_address_from_create_asset(create_asset_request: CreateAssetRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + +pub fn get_driver_address_from_extinguish(extinguish_request: ExtinguishRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + +pub fn get_driver_address_from_assign_asset(assign_asset_request: AssignAssetRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 14e970b4a5..e33e3610d9 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,6 +1,8 @@ // Internal generated modules use weaverpb::common::ack::{ack, Ack}; -use weaverpb::driver::driver::PerformLockRequest; +use weaverpb::driver::driver::{ + AssignAssetRequest, CreateAssetRequest, ExtinguishRequest, PerformLockRequest, +}; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{ AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, @@ -14,7 +16,8 @@ use crate::error::Error; use crate::relay_proto::parse_address; use crate::services::helpers::{println_stage_heading, println_step_heading}; use crate::services::satp_helper::{ - create_ack_error_message, create_perform_lock_request, + create_ack_error_message, create_assign_asset_request, create_create_asset_request, + create_extinguish_request, create_perform_lock_request, get_request_id_from_transfer_proposal_receipt, log_request_in_local_satp_db, log_request_in_remote_satp_db, }; @@ -26,10 +29,12 @@ use super::satp_helper::{ create_commit_final_assertion_request, create_commit_prepare_request, create_commit_ready_request, create_lock_assertion_request, create_transfer_commence_request, create_transfer_completed_request, create_transfer_proposal_receipt_request, - get_driver_address_from_perform_lock, get_relay_from_ack_commence, - get_relay_from_ack_final_receipt, get_relay_from_commit_final_assertion, - get_relay_from_commit_prepare, get_relay_from_commit_ready, get_relay_from_lock_assertion, - get_relay_from_transfer_commence, get_relay_from_transfer_proposal_receipt, get_relay_params, + get_driver_address_from_assign_asset, get_driver_address_from_create_asset, + get_driver_address_from_extinguish, get_driver_address_from_perform_lock, + get_relay_from_ack_commence, get_relay_from_ack_final_receipt, + get_relay_from_commit_final_assertion, get_relay_from_commit_prepare, + get_relay_from_commit_ready, get_relay_from_lock_assertion, get_relay_from_transfer_commence, + get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, spawn_send_ack_final_receipt_broadcast_request, spawn_send_ack_final_receipt_request, spawn_send_assign_asset_request, spawn_send_commit_final_assertion_request, @@ -785,7 +790,8 @@ pub fn process_ack_commence_request( // TODO some processing if is_valid_request { println!("The ack commence request is valid\n"); - let perform_lock_request = create_perform_lock_request(ack_commence_request); + let perform_lock_request: PerformLockRequest = + create_perform_lock_request(ack_commence_request); match send_perform_lock_request(perform_lock_request, conf) { Ok(ack) => { println!("Ack ack commence request."); @@ -963,7 +969,9 @@ pub fn process_commit_prepare_request( // TODO some processing if is_valid_request { println!("The commit prepare request is valid\n"); - match send_create_asset_request(commit_prepare_request, conf) { + let create_asset_request: CreateAssetRequest = + create_create_asset_request(commit_prepare_request); + match send_create_asset_request(create_asset_request, conf) { Ok(ack) => { println!("Ack commit prepare request."); let reply = Ok(ack); @@ -998,7 +1006,8 @@ pub fn process_commit_ready_request( // TODO some processing if is_valid_request { println!("The commit ready request is valid\n"); - match send_extinguish_request(commit_ready_request, conf) { + let extinguish_request: ExtinguishRequest = create_extinguish_request(commit_ready_request); + match send_extinguish_request(extinguish_request, conf) { Ok(ack) => { println!("Ack commit ready request."); let reply = Ok(ack); @@ -1034,7 +1043,9 @@ pub fn process_commit_final_assertion_request( // TODO some processing if is_valid_request { println!("The commit final assertion request is valid\n"); - match send_assign_asset_request(commit_final_assertion_request, conf) { + let assign_asset_request: AssignAssetRequest = + create_assign_asset_request(commit_final_assertion_request); + match send_assign_asset_request(assign_asset_request, conf) { Ok(ack) => { println!("Ack commit final assertion request."); let reply = Ok(ack); @@ -1312,59 +1323,72 @@ fn send_commit_ready_request( } fn send_create_asset_request( - commit_prepare_request: CommitPrepareRequest, + create_asset_request: CreateAssetRequest, conf: config::Config, ) -> Result { // TODO println_step_heading("3.2A".to_string()); - let request_id = &commit_prepare_request.session_id.to_string(); - let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); - let (use_tls, tlsca_cert_path) = - get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - spawn_send_create_asset_request( - commit_prepare_request, - relay_host, - relay_port, - use_tls, - tlsca_cert_path, - conf, - ); + let request_id = &create_asset_request.session_id.to_string(); + let driver_address = get_driver_address_from_create_asset(create_asset_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request_id.to_string(), - message: "Ack of the commit prepare request".to_string(), - }; - return Ok(reply); + match result { + Ok(driver_info) => { + spawn_send_create_asset_request(driver_info, create_asset_request); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the commit prepare request failed. Driver not found {:?}", + e + ), + }); + } + } } fn send_extinguish_request( - commit_ready_request: CommitReadyRequest, + extinguish_request: ExtinguishRequest, conf: config::Config, ) -> Result { // TODO println_step_heading("3.4A".to_string()); - let request_id = &commit_ready_request.session_id.to_string(); - let (relay_host, relay_port) = get_relay_from_commit_ready(commit_ready_request.clone()); - let (use_tls, tlsca_cert_path) = - get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - - spawn_send_extinguish_request( - commit_ready_request, - relay_host, - relay_port, - use_tls, - tlsca_cert_path, - conf, - ); + let request_id = &extinguish_request.session_id.to_string(); + let driver_address = get_driver_address_from_extinguish(extinguish_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request_id.to_string(), - message: "Ack of the commit prepare request".to_string(), - }; - return Ok(reply); + match result { + Ok(driver_info) => { + spawn_send_extinguish_request(driver_info, extinguish_request); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the commit prepare request failed. Driver not found {:?}", + e + ), + }); + } + } } fn send_commit_final_assertion_request( @@ -1400,7 +1424,6 @@ fn send_ack_final_receipt_request( conf: config::Config, ) -> Result { // TODO - println_step_heading("3.8".to_string()); let request_id = &ack_final_receipt_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); @@ -1425,32 +1448,37 @@ fn send_ack_final_receipt_request( } fn send_assign_asset_request( - commit_final_assertion_request: CommitFinalAssertionRequest, + assign_asset_request: AssignAssetRequest, conf: config::Config, ) -> Result { // TODO println_step_heading("3.6A".to_string()); - let request_id = &commit_final_assertion_request.session_id.to_string(); - let (relay_host, relay_port) = - get_relay_from_commit_final_assertion(commit_final_assertion_request.clone()); - let (use_tls, tlsca_cert_path) = - get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - - spawn_send_assign_asset_request( - commit_final_assertion_request, - relay_host, - relay_port, - use_tls, - tlsca_cert_path, - conf, - ); + let request_id = &assign_asset_request.session_id.to_string(); + let driver_address = get_driver_address_from_assign_asset(assign_asset_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request_id.to_string(), - message: "Ack of the commit prepare request".to_string(), - }; - return Ok(reply); + match result { + Ok(driver_info) => { + spawn_send_assign_asset_request(driver_info, assign_asset_request); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit final assertion request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the commit final assertion request failed. Driver not found {:?}", + e + ), + }); + } + } } fn send_ack_final_receipt_broadcast_request( @@ -1458,6 +1486,7 @@ fn send_ack_final_receipt_broadcast_request( conf: config::Config, ) -> Result { // TODO + println_step_heading("3.8".to_string()); let request_id = &ack_final_receipt_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); From e7b7d38e09e09d6d0f748939856c0fafa147d7bd Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 11 Sep 2023 20:44:08 +0100 Subject: [PATCH 25/59] Added the resources required to assign an asset --- tools/go-gen-checksum.sh | 1 + .../core/drivers/fabric-driver/server/satp.ts | 213 +++- .../core/relay/src/services/satp_service.rs | 4 +- .../samples/fabric/satpsimpleasset/.gitignore | 4 + .../samples/fabric/satpsimpleasset/Makefile | 27 + .../fabric/satpsimpleasset/assetmgmt.go | 360 ++++++ .../fabric/satpsimpleasset/assetmgmt_test.go | 232 ++++ .../fabric/satpsimpleasset/bondasset.go | 327 +++++ .../fabric/satpsimpleasset/bondasset_test.go | 242 ++++ weaver/samples/fabric/satpsimpleasset/go.mod | 42 + weaver/samples/fabric/satpsimpleasset/go.sum | 157 +++ .../samples/fabric/satpsimpleasset/helper.go | 53 + weaver/samples/fabric/satpsimpleasset/main.go | 59 + .../fabric/satpsimpleasset/tokenasset.go | 316 +++++ .../fabric/satpsimpleasset/tokenasset_test.go | 326 +++++ .../fabric/interoperation-node-sdk/index.js | 1 + .../src/AssetManager.ts | 59 + .../src/SatpAssetManager.ts | 1111 +++++++++++++++++ .../interoperation-node-sdk/types/index.d.ts | 2 + .../fabric/dev/scripts/deployCC.sh | 4 + 20 files changed, 3519 insertions(+), 21 deletions(-) create mode 100644 weaver/samples/fabric/satpsimpleasset/.gitignore create mode 100644 weaver/samples/fabric/satpsimpleasset/Makefile create mode 100644 weaver/samples/fabric/satpsimpleasset/assetmgmt.go create mode 100644 weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go create mode 100644 weaver/samples/fabric/satpsimpleasset/bondasset.go create mode 100644 weaver/samples/fabric/satpsimpleasset/bondasset_test.go create mode 100644 weaver/samples/fabric/satpsimpleasset/go.mod create mode 100644 weaver/samples/fabric/satpsimpleasset/go.sum create mode 100644 weaver/samples/fabric/satpsimpleasset/helper.go create mode 100644 weaver/samples/fabric/satpsimpleasset/main.go create mode 100644 weaver/samples/fabric/satpsimpleasset/tokenasset.go create mode 100644 weaver/samples/fabric/satpsimpleasset/tokenasset_test.go create mode 100644 weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts diff --git a/tools/go-gen-checksum.sh b/tools/go-gen-checksum.sh index 87ef776051..513a5afd04 100755 --- a/tools/go-gen-checksum.sh +++ b/tools/go-gen-checksum.sh @@ -16,6 +16,7 @@ GOMODULE_PATHS=("weaver/core/network/fabric-interop-cc/libs/utils" "weaver/sdks/fabric/go-sdk" "weaver/samples/fabric/go-cli" "weaver/samples/fabric/simpleasset" +"weaver/samples/fabric/satpsimpleasset" "weaver/samples/fabric/simpleassetandinterop" "weaver/samples/fabric/simpleassettransfer" "weaver/samples/fabric/simplestatewithacl" diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index fea151a0c3..0f0eef77b5 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -5,7 +5,7 @@ import logger from './logger'; import { credentials } from '@grpc/grpc-js'; import { getNetworkConfig } from './helpers/helpers' -import { AssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' +import { SatpAssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' import fs from 'fs'; import path from 'path'; @@ -23,6 +23,7 @@ async function performLockHelper( networkName: string ): Promise { + // TODO: remove the hardcoded values let performLockRequest2 = {}; performLockRequest2['target-network'] = 'network1'; performLockRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; @@ -31,11 +32,12 @@ async function performLockHelper( performLockRequest2['recipient'] = 'bob'; performLockRequest2['param'] = 'bond01:a05'; - // Locker and Recipient + // Locker and recipient const locker = performLockRequest2['locker']; const recipient = performLockRequest2['recipient']; let hashFn = performLockRequest2['hash_fn']; let hashBase64 = performLockRequest2['hashBase64']; + const targetNetwork = performLockRequest2['target-network']; // Hash let hash: HashFunctions.Hash @@ -66,11 +68,11 @@ async function performLockHelper( } const params = performLockRequest2['param'].split(':') - const netConfig = getNetworkConfig(performLockRequest2['target-network']) + const netConfig = getNetworkConfig(targetNetwork) if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { console.error( - `Please use a valid --target-network. No valid environment found for ${performLockRequest2['target-network']} ` + `Please use a valid --target-network. No valid environment found for ${targetNetwork} ` ) return } @@ -79,7 +81,7 @@ async function performLockHelper( channel: netConfig.channelName, contractName: netConfig.chaincode, connProfilePath: netConfig.connProfilePath, - networkName: performLockRequest2['target-network'], + networkName: targetNetwork, mspId: netConfig.mspId, userString: locker }) @@ -92,14 +94,14 @@ async function performLockHelper( var funcToCall, asset if (performLockRequest2['fungible']) { - funcToCall = AssetManager.createFungibleHTLC + funcToCall = SatpAssetManager.createFungibleHTLC asset = 'Fungible Asset' } else { - funcToCall = AssetManager.createHTLC + funcToCall = SatpAssetManager.createHTLC asset = 'Asset' } - console.info(`Asset Exchange: Lock ${asset}:\n`); + console.info(`Asset Lock: Lock ${asset}:\n`); try { console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) // const res = await funcToCall(network.contract, @@ -113,14 +115,12 @@ async function performLockHelper( // throw new Error() // } // console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) - console.info('Asset Exchange: Lock Complete.') + console.info('Asset has been locked successfully') } catch (error) { - console.error(`Could not Lock ${asset} in ${performLockRequest2['target-network']}`) + console.error(`Could not Lock ${asset} in ${targetNetwork}`) } - // await new Promise(f => setTimeout(f, performLockRequest2['timeout-duration'] * 1000 + 3000)); - await network.gateway.disconnect() logger.info('Gateways disconnected.') @@ -136,7 +136,88 @@ async function createAssetHelper( networkName: string ): Promise { - // TODO + // TODO: remove the hardcoded values + let createAssetRequest2 = {}; + createAssetRequest2['target-network'] = 'network1'; + createAssetRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; + createAssetRequest2['timeout-duration'] = parseInt('3600'); + createAssetRequest2['owner'] = 'admin'; + createAssetRequest2['type'] = 'bond'; + createAssetRequest2['assetType'] = 'bond01'; + createAssetRequest2['id'] = 'a065'; + createAssetRequest2['issuer'] = 'admin'; + createAssetRequest2['facevalue'] = '300'; + createAssetRequest2['maturitydate'] = '05 May 48 00:00 MST'; + + const targetNetwork = createAssetRequest2['target-network']; + const owner = createAssetRequest2['owner']; + const ccType = createAssetRequest2['type']; + const assetType = createAssetRequest2['assetType']; + const id = createAssetRequest2['id']; + const issuer = createAssetRequest2['issuer']; + const facevalue = createAssetRequest2['facevalue']; + const maturitydate = createAssetRequest2['maturitydate']; + const tokenassettype = createAssetRequest2['tokenassettype']; + const numunits = createAssetRequest2['numunits']; + + const netConfig = getNetworkConfig(targetNetwork) + console.info(netConfig) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + console.error( + `Please use a valid --target-network. No valid environment found for ${targetNetwork} ` + ) + return + } + + const currentQuery = { + channel: netConfig.channelName, + contractName: netConfig.chaincode, + ccFunc: '', + args: [] + } + + const network = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: targetNetwork, + mspId: netConfig.mspId, + userString: owner, + registerUser: false + }) + + const userId = await network.wallet.get(owner) + const userCert = Buffer.from((userId).credentials.certificate).toString('base64') + + if (ccType == 'bond') { + currentQuery.ccFunc = 'CreateAsset' + currentQuery.args = [...currentQuery.args, assetType, id, userCert, issuer, facevalue, maturitydate] + } else if (ccType == 'token') { + currentQuery.ccFunc = 'IssueTokenAssets' + currentQuery.args = [...currentQuery.args, tokenassettype, numunits, userCert] + } else { + throw new Error(`Unrecognized asset category: ${ccType}`) + } + console.log(currentQuery) + + try { + console.info(`Trying creating the asset: type: ${ccType}, id: ${id}, by: ${owner}, facevalue: ${facevalue}, maturitydate: ${maturitydate}`) + const read = await network.contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + console.info('Asset has been created successfully') + } else { + logger.debug('No Response from network') + } + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } + + await network.gateway.disconnect() + logger.info('Gateways disconnected.') + const client = getRelayClientForAssetStatusResponse(); const request = new satp_pb.SendAssetStatusRequest(); request.setSessionId(createAssetRequest.getSessionId()); @@ -162,12 +243,106 @@ async function assignAssetHelper( networkName: string ): Promise { - // TODO - const client = getRelayClientForAssetStatusResponse(); - const request = new satp_pb.SendAssetStatusRequest(); - request.setSessionId(assignAssetRequest.getSessionId()); - request.setStatus("Finalized"); - client.sendAssetStatus(request, relayCallback); + // TODO: remove the hardcoded values + let assignAssetRequest2 = {}; + assignAssetRequest2['target-network'] = 'network1'; + assignAssetRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; + assignAssetRequest2['timeout-duration'] = parseInt('3600'); + assignAssetRequest2['locker'] = 'admin'; + assignAssetRequest2['recipient'] = 'bob'; + assignAssetRequest2['fungible'] = false; + assignAssetRequest2['contract-id'] = 'abc01'; + assignAssetRequest2['hash_fn'] = ''; + assignAssetRequest2['secret'] = 'secrettext'; + assignAssetRequest2['param'] = 'bond01:a065'; + + const targetNetwork = assignAssetRequest2['target-network']; + const locker = assignAssetRequest2['locker']; + const recipient = assignAssetRequest2['recipient']; + const fungible = assignAssetRequest2['fungible']; + const hashFn = assignAssetRequest2['hash_fn']; + const secret = assignAssetRequest2['secret']; + + // Hash + let hash: HashFunctions.Hash + if (hashFn == 'SHA512') { + hash = new HashFunctions.SHA512() + } else { + hash = new HashFunctions.SHA256() + } + hash.setPreimage(secret) + + let contractId: string = null, params + if (assignAssetRequest2['contract-id']) { + contractId = assignAssetRequest2['contract-id'] + } + + params = assignAssetRequest2['param'].split(':') + + const netConfig = getNetworkConfig(targetNetwork) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + console.error( + `Please use a valid --target-network. No valid environment found for ${targetNetwork} ` + ) + return + } + + const network = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: targetNetwork, + mspId: netConfig.mspId, + userString: recipient + }) + + var funcToCall = SatpAssetManager.assignAsset + var asset = assignAssetRequest2['param'] + + if (assignAssetRequest2['fungible']) { + // funcToCall = SatpAssetManager.claimFungibleAssetInHTLC + asset = 'Fungible Asset' + } + + if (fungible) { + try { + console.info(`Trying assigning the asset with contract id ${contractId}`) + + // TODO + } catch (error) { + console.error(`Could not assign ${asset} in ${targetNetwork}`) + throw new Error(`Could not assign ${asset} in ${targetNetwork}`) + } + } else { + try { + const lockerId = await network.wallet.get(locker) + const lockerCert = Buffer.from((lockerId).credentials.certificate).toString('base64') + + console.info(`Trying assign asset with params: ${params[0]}, ${params[1]} locked by ${locker} for ${recipient}`) + const res = await funcToCall(network.contract, + params[0], + params[1], + lockerCert, + hash) + if (!res) { + throw new Error() + } + console.info(`${asset} assigned complete: ${res}`) + console.info(`Asset ${asset} assign complete: ${res}`) + } catch (error) { + console.error(`Could not assign non-fungible ${asset} in ${targetNetwork}: ${error}`) + throw new Error(`Could not assign non-fungible ${asset} in ${targetNetwork}: ${error}`) + } + + await network.gateway.disconnect() + logger.info('Gateways disconnected.') + + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(assignAssetRequest.getSessionId()); + request.setStatus("Finalized"); + client.sendAssetStatus(request, relayCallback); + } } function getRelayClientForAssetStatusResponse() { diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index e33e3610d9..7ed1536339 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1414,7 +1414,7 @@ fn send_commit_final_assertion_request( let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), - message: "Ack of the commit prepare request".to_string(), + message: "Commit final assertion request sent".to_string(), }; return Ok(reply); } @@ -1442,7 +1442,7 @@ fn send_ack_final_receipt_request( let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), - message: "Ack of the commit prepare request".to_string(), + message: "Ack final receipt request sent".to_string(), }; return Ok(reply); } diff --git a/weaver/samples/fabric/satpsimpleasset/.gitignore b/weaver/samples/fabric/satpsimpleasset/.gitignore new file mode 100644 index 0000000000..6e83e63f95 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/.gitignore @@ -0,0 +1,4 @@ +satpsimpleasset +asset-mgmt +mocks +vendor diff --git a/weaver/samples/fabric/satpsimpleasset/Makefile b/weaver/samples/fabric/satpsimpleasset/Makefile new file mode 100644 index 0000000000..0b11edb7ab --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/Makefile @@ -0,0 +1,27 @@ +run-vendor: + go mod edit -replace github.com/hyperledger/cacti/weaver/common/protos-go/v2=../../../common/protos-go/ + go mod edit -replace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2=../../../core/network/fabric-interop-cc/interfaces/asset-mgmt/ + go mod edit -replace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils=../../../core/network/fabric-interop-cc/libs/testutils/ + go mod vendor + +undo-vendor: + rm -rf vendor + go mod edit -dropreplace github.com/hyperledger/cacti/weaver/common/protos-go/v2 + go mod edit -dropreplace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 + go mod edit -dropreplace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils + +build-local: run-vendor build undo-vendor + +test-local: run-vendor test undo-vendor + +build: + go build -v . + +test: + go test -v . + +clean-vendor: + rm -rf vendor + +clean: clean-vendor + rm satpsimpleasset diff --git a/weaver/samples/fabric/satpsimpleasset/assetmgmt.go b/weaver/samples/fabric/satpsimpleasset/assetmgmt.go new file mode 100644 index 0000000000..384c4c3c96 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/assetmgmt.go @@ -0,0 +1,360 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package main + +import ( + "encoding/json" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/cacti/weaver/common/protos-go/v2/common" + "github.com/hyperledger/fabric-contract-api-go/contractapi" + log "github.com/sirupsen/logrus" +) + +// asset specific checks (ideally an asset in a different application might implement checks specific to that asset) +func (s *SmartContract) BondAssetSpecificChecks(ctx contractapi.TransactionContextInterface, assetType, id string, lockInfoSerializedProto64 string) error { + + lockInfo, err := s.amc.ValidateAndExtractLockInfo(lockInfoSerializedProto64) + if err != nil { + return err + } + lockInfoHTLC := &common.AssetLockHTLC{} + err = proto.Unmarshal(lockInfo.LockInfo, lockInfoHTLC) + if err != nil { + return logThenErrorf("unmarshal error: %+v", err) + } + // ReadAsset should check both the existence and ownership of the asset for the locker + bond, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return logThenErrorf("failed reading the bond asset: %+v", err) + } + log.Infof("bond: %+v", *bond) + log.Infof("lockInfoHTLC: %+v", *lockInfoHTLC) + + // Check if asset doesn't mature before locking period + if uint64(bond.MaturityDate.Unix()) < lockInfoHTLC.ExpiryTimeSecs { + return logThenErrorf("cannot lock bond asset as it will mature before locking period") + } + + return nil +} + +// Ledger transaction (invocation) functions + +func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) { + + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetExchangeAgreementSerializedProto64) + if err != nil { + return "", err + } + err = s.BondAssetSpecificChecks(ctx, assetAgreement.AssetType, assetAgreement.Id, lockInfoSerializedProto64) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + contractId, err := s.amc.LockAsset(ctx, assetExchangeAgreementSerializedProto64, lockInfoSerializedProto64) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + // write to the ledger the details needed at the time of unlock/claim + err = s.amc.ContractIdAssetsLookupMap(ctx, assetAgreement.AssetType, assetAgreement.Id, contractId) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + return contractId, nil +} + +func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) { + + assetAgreement, err := s.amc.ValidateAndExtractFungibleAssetAgreement(fungibleAssetExchangeAgreementSerializedProto64) + if err != nil { + return "", err + } + lockInfo, err := s.amc.ValidateAndExtractLockInfo(lockInfoSerializedProto64) + if err != nil { + return "", err + } + lockInfoHTLC := &common.AssetLockHTLC{} + err = proto.Unmarshal(lockInfo.LockInfo, lockInfoHTLC) + if err != nil { + return "", logThenErrorf("unmarshal error: %+v", err) + } + + // Check if locker/transaction-creator has enough quantity of token assets to lock + lockerHasEnoughTokens, err := s.TokenAssetsExist(ctx, assetAgreement.AssetType, assetAgreement.NumUnits) + if err != nil { + return "", logThenErrorf(err.Error()) + } + if !lockerHasEnoughTokens { + return "", logThenErrorf("cannot lock token asset of type %s as there are not enough tokens", assetAgreement.AssetType) + } + + contractId, err := s.amc.LockFungibleAsset(ctx, fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + err = s.DeleteTokenAssets(ctx, assetAgreement.AssetType, assetAgreement.NumUnits) + if err != nil { + // not performing the operation UnlockFungibleAsset and let the TxCreator take care of it + return contractId, logThenErrorf(err.Error()) + } + + err = s.amc.ContractIdFungibleAssetsLookupMap(ctx, assetAgreement.AssetType, assetAgreement.NumUnits, contractId) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + return contractId, nil +} + +// Check whether this asset has been locked by anyone (not just by caller) +func (s *SmartContract) IsAssetLocked(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string) (bool, error) { + return s.amc.IsAssetLocked(ctx, assetAgreementSerializedProto64) +} + +// Check whether a bond asset has been locked using contractId by anyone (not just by caller) +func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + return s.amc.IsAssetLockedQueryUsingContractId(ctx, contractId) +} + +// Check whether a token asset has been locked using contractId by anyone (not just by caller) +func (s *SmartContract) IsFungibleAssetLocked(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + return s.amc.IsFungibleAssetLocked(ctx, contractId) +} + +func (s *SmartContract) ClaimAsset(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string, claimInfoSerializedProto64 string) (bool, error) { + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetAgreementSerializedProto64) + if err != nil { + return false, err + } + claimed, err := s.amc.ClaimAsset(ctx, assetAgreementSerializedProto64, claimInfoSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if claimed { + // Change asset ownership to claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset, err := getBondAsset(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset.Owner = string(recipientECertBase64) + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = ctx.GetStub().PutState(getBondAssetKey(assetAgreement.AssetType, assetAgreement.Id), assetJSON) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + err = s.amc.DeleteAssetLookupMaps(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf("failed to delete bond asset lookup maps: %+v", err) + } + + return true, nil + } else { + return false, logThenErrorf("claim on bond asset type %s with asset id %s failed", assetAgreement.AssetType, assetAgreement.Id) + } +} + +func (s *SmartContract) AssignAsset(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string, claimInfoSerializedProto64 string) (bool, error) { + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetAgreementSerializedProto64) + if err != nil { + return false, err + } + + // Change asset ownership to claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset, err := getBondAsset(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset.Owner = string(recipientECertBase64) + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = ctx.GetStub().PutState(getBondAssetKey(assetAgreement.AssetType, assetAgreement.Id), assetJSON) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + return true, nil +} + +func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) { + claimed, err := s.amc.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if claimed { + // Change asset ownership to claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + // Fetch the contracted bond asset type and id from the ledger + assetType, assetId, err := s.amc.FetchFromContractIdAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + asset, err := getBondAsset(ctx, assetType, assetId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset.Owner = recipientECertBase64 + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = ctx.GetStub().PutState(getBondAssetKey(assetType, assetId), assetJSON) + if err != nil { + return false, logThenErrorf(err.Error()) + } + // delete the lookup maps + err = s.amc.DeleteAssetLookupMapsUsingContractId(ctx, assetType, assetId, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + return true, nil + } else { + return false, logThenErrorf("claim on bond asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) ClaimFungibleAsset(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) { + claimed, err := s.amc.ClaimFungibleAsset(ctx, contractId, claimInfoSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if claimed { + // Add the claimed tokens into the wallet of the claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + // Fetch the contracted token asset type and numUnits from the ledger + assetType, numUnits, err := s.amc.FetchFromContractIdFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + err = s.IssueTokenAssets(ctx, assetType, numUnits, recipientECertBase64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = s.amc.DeleteFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + return true, nil + } else { + return false, logThenErrorf("claim on token asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) UnlockAsset(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string) (bool, error) { + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetAgreementSerializedProto64) + if err != nil { + return false, err + } + + unlocked, err := s.amc.UnlockAsset(ctx, assetAgreementSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if unlocked { + err = s.amc.DeleteAssetLookupMaps(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf("failed to delete bond asset lookup maps: %+v", err) + } + } else { + return false, logThenErrorf("unlock on bond asset type %s with asset id %s failed", assetAgreement.AssetType, assetAgreement.Id) + } + + return true, nil +} + +func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + unlocked, err := s.amc.UnlockAssetUsingContractId(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if unlocked { + // delete the lookup maps + err := s.amc.DeleteAssetLookupMapsOnlyUsingContractId(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + return true, nil + } else { + return false, logThenErrorf("unlock on bond asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) UnlockFungibleAsset(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + unlocked, err := s.amc.UnlockFungibleAsset(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if unlocked { + // Add the unlocked tokens into the wallet of the locker + lockerECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + // Fetch the contracted token asset type and numUnits from the ledger + assetType, numUnits, err := s.amc.FetchFromContractIdFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + err = s.IssueTokenAssets(ctx, assetType, numUnits, lockerECertBase64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = s.amc.DeleteFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + return true, nil + } else { + return false, logThenErrorf("unlock on token asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) GetHTLCHash(ctx contractapi.TransactionContextInterface, assetAgreementBytesBase64 string) (string, error) { + return s.amc.GetHTLCHash(ctx, assetAgreementBytesBase64) +} + +func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) { + return s.amc.GetHTLCHashByContractId(ctx, contractId) +} + +func (s *SmartContract) GetHTLCHashPreImage(ctx contractapi.TransactionContextInterface, assetAgreementBytesBase64 string) (string, error) { + return s.amc.GetHTLCHashPreImage(ctx, assetAgreementBytesBase64) +} + +func (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) { + return s.amc.GetHTLCHashPreImageByContractId(ctx, contractId) +} diff --git a/weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go b/weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go new file mode 100644 index 0000000000..83db59decd --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go @@ -0,0 +1,232 @@ +package main_test + +import ( + "encoding/json" + "encoding/base64" + "crypto/sha256" + "fmt" + "testing" + "time" + + mspProtobuf "github.com/hyperledger/fabric-protos-go/msp" + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric-chaincode-go/shim" + "github.com/stretchr/testify/require" + sa "github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset" + "github.com/hyperledger/cacti/weaver/common/protos-go/v2/common" + wtest "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils" +) + +// function that supplies value that is to be returned by ctx.GetStub().GetCreator() in locker/recipient context +func getCreatorInContext(creator string) string { + serializedIdentity := &mspProtobuf.SerializedIdentity{} + var eCertBytes []byte + if creator == "locker" { + eCertBytes, _ = base64.StdEncoding.DecodeString(getLockerECertBase64()) + } else { + eCertBytes, _ = base64.StdEncoding.DecodeString(getRecipientECertBase64()) + } + serializedIdentity.IdBytes = eCertBytes + serializedIdentity.Mspid = "ca.org1.example.com" + serializedIdentityBytes, _ := proto.Marshal(serializedIdentity) + + return string(serializedIdentityBytes) +} + +// function that supplies the ECert in base64 for locker (e.g., Alice) +func getLockerECertBase64() string { + eCertBase64 := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNyVENDQWxTZ0F3SUJBZ0lVSENXLzBtV0xhc2hISG9zd0xxVWhpK1FwREc4d0NnWUlLb1pJemowRUF3SXcKY2pFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1ROHdEUVlEVlFRSApFd1pFZFhKb1lXMHhHakFZQmdOVkJBb1RFVzl5WnpFdWJtVjBkMjl5YXpFdVkyOXRNUjB3R3dZRFZRUURFeFJqCllTNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQWVGdzB5TURBM01qa3dORE0yTURCYUZ3MHlNVEEzTWprd05EUXgKTURCYU1GMHhDekFKQmdOVkJBWVRBbFZUTVJjd0ZRWURWUVFJRXc1T2IzSjBhQ0JEWVhKdmJHbHVZVEVVTUJJRwpBMVVFQ2hNTFNIbHdaWEpzWldSblpYSXhEekFOQmdOVkJBc1RCbU5zYVdWdWRERU9NQXdHQTFVRUF4TUZkWE5sCmNqRXdXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBU3VoL3JWQ2Y4T0R1dzBJaG5yTTJpaWYyYTcKc0dUOEJJVjFQRURVM1NucUNsbWgrUlYvM0p5S2wvVHl0aHpOL1pWbktFL3R2NWQzZ1ZXYk5zdGM5NytTbzRIYwpNSUhaTUE0R0ExVWREd0VCL3dRRUF3SUhnREFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCUXgvaExZCkNORzRlekNxdmdUS0MvV3d1U1ZubURBZkJnTlZIU01FR0RBV2dCVFdENjArZUNIYkR5RDMzUFdiQ3hWdVFxTUEKcVRBZkJnTlZIUkVFR0RBV2doUnZZelV4TURNM05EY3pPREF1YVdKdExtTnZiVEJZQmdncUF3UUZCZ2NJQVFSTQpleUpoZEhSeWN5STZleUpvWmk1QlptWnBiR2xoZEdsdmJpSTZJaUlzSW1obUxrVnVjbTlzYkcxbGJuUkpSQ0k2CkluVnpaWEl4SWl3aWFHWXVWSGx3WlNJNkltTnNhV1Z1ZENKOWZUQUtCZ2dxaGtqT1BRUURBZ05IQURCRUFpQUYKbnNMNlV1eFRtSks5bmhkTU1QNWxWN3hueVlsMVd5RGl6RVFzZnd1T1p3SWdYY3duSE9hVURXWWpmWHRGU0k1eQp6WjltcjZQRWtSNER0VEhJUkZhTVYxOD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==" + + return eCertBase64 +} + +// function that supplies the ECert in base64 for recipient (e.g., Bob) +func getRecipientECertBase64() string { + eCertBase64 := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNzekNDQWxxZ0F3SUJBZ0lVSjk3ZDJaWUNkRkNHbFo5L3hmZHRlcUdMc1Jvd0NnWUlLb1pJemowRUF3SXcKY2pFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1ROHdEUVlEVlFRSApFd1pFZFhKb1lXMHhHakFZQmdOVkJBb1RFVzl5WnpFdWJtVjBkMjl5YXpFdVkyOXRNUjB3R3dZRFZRUURFeFJqCllTNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQWVGdzB5TURBM01qa3dORE0yTURCYUZ3MHlNVEEzTWprd05EUXgKTURCYU1HQXhDekFKQmdOVkJBWVRBbFZUTVJjd0ZRWURWUVFJRXc1T2IzSjBhQ0JEWVhKdmJHbHVZVEVVTUJJRwpBMVVFQ2hNTFNIbHdaWEpzWldSblpYSXhEakFNQmdOVkJBc1RCV0ZrYldsdU1SSXdFQVlEVlFRREV3bHZjbWN4CllXUnRhVzR3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFmbjRmVHRDclQ3WVMrZVI1WWRFVU8KMHRKWmJGaEtyYUdqeWVNM2tBTzNNN1VHdVBsUCtXcFdjNkNYUEx3bTNETHgrcjFhMUx6eW1KUWdaOVJjdXErcgpvNEhmTUlIY01BNEdBMVVkRHdFQi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlM2ClkxR1FCMXAwUlNBeWxjTTRxQTlZS0JkU2hEQWZCZ05WSFNNRUdEQVdnQlRXRDYwK2VDSGJEeUQzM1BXYkN4VnUKUXFNQXFUQWZCZ05WSFJFRUdEQVdnaFJ2WXpVeE1ETTNORGN6T0RBdWFXSnRMbU52YlRCYkJnZ3FBd1FGQmdjSQpBUVJQZXlKaGRIUnljeUk2ZXlKb1ppNUJabVpwYkdsaGRHbHZiaUk2SWlJc0ltaG1Ma1Z1Y205c2JHMWxiblJKClJDSTZJbTl5WnpGaFpHMXBiaUlzSW1obUxsUjVjR1VpT2lKaFpHMXBiaUo5ZlRBS0JnZ3Foa2pPUFFRREFnTkgKQURCRUFpQkwrSzAzVGFFeWJaRkdWMmMzSS81ZXlpMFBveGc2elZOWDJkajJWRlk5WWdJZ0w5ZlhzcWhaUEU0VApBSkU4ZVZqdWZaOVJnNERJWWloTVVTKzBPbGpWL3pBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t" + return eCertBase64 +} + +// function to generate a "SHA256" hash in base64 format for a given preimage +func generateSHA256HashInBase64Form(preimage string) string { + hasher := sha256.New() + hasher.Write([]byte(preimage)) + shaHash := hasher.Sum(nil) + shaHashBase64 := base64.StdEncoding.EncodeToString(shaHash) + return shaHashBase64 +} + +type ContractedFungibleAsset struct { + Type string `json:"type"` + NumUnits uint64 `json:"id"` +} + +// test case for "asset exchange" happy path +func TestExchangeBondAssetWithTokenAsset(t *testing.T) { + ctx, chaincodeStub := wtest.PrepMockStub() + sc := sa.SmartContract{} + sc.ConfigureInterop("interopcc") + + bondLocker := getLockerECertBase64() + bondRecipient := getRecipientECertBase64() + bondType := "bond" + bondId := "b01" + bondIssuer := "network1" + bondFaceValue := 1 + currentTime := time.Now() + bondMaturityDate := currentTime.Add(time.Hour * 24) // maturity date is 1 day after current time + + tokenType := "cbdc" + tokenIssuer := "network2" + tokenValue := 1 + numTokens := uint64(10) + tokensLocker := getRecipientECertBase64() + tokensRecipient := getLockerECertBase64() + + + // Create bond asset + // let ctx.GetStub().GetState() return that the bond asset didn't exist before + chaincodeStub.GetStateReturnsOnCall(0, nil, nil) + err := sc.CreateAsset(ctx, bondType, bondId, bondLocker, bondIssuer, bondFaceValue, bondMaturityDate.Format(time.RFC822)) + require.NoError(t, err) + + + // Create token asset type + chaincodeStub.GetStateReturnsOnCall(1, nil, nil) + res, err := sc.CreateTokenAssetType(ctx, tokenType, tokenIssuer, tokenValue) + require.NoError(t, err) + require.Equal(t, res, true) + + + // Issue token assets for Bob + tokenAssetType := sa.TokenAssetType { + Issuer: tokenIssuer, + Value: tokenValue, + } + tokenAssetTypeBytes, _ := json.Marshal(tokenAssetType) + chaincodeStub.GetStateReturnsOnCall(2, tokenAssetTypeBytes, nil) + walletMap := make(map[string]uint64) + tokensWallet := &sa.TokenWallet{WalletMap: walletMap} + tokensWalletBytes, _ := json.Marshal(tokensWallet) + chaincodeStub.GetStateReturnsOnCall(3, tokensWalletBytes, nil) + err = sc.IssueTokenAssets(ctx, tokenType, numTokens, getRecipientECertBase64()) + require.NoError(t, err) + + + // Lock bond asset in network1 by Alice for Bob + fmt.Println("*** Lock bond asset in network1 by Alice ***") + preimage := "abcd" + hashBase64 := generateSHA256HashInBase64Form(preimage) + defaultTimeLockSecs := uint64(300) // set default locking period as 5 minutes + currentTimeSecs := uint64(time.Now().Unix()) + bondContractId := "bond-contract" + lockInfoHTLC := &common.AssetLockHTLC { + HashBase64: []byte(hashBase64), + ExpiryTimeSecs: currentTimeSecs + defaultTimeLockSecs, + TimeSpec: common.TimeSpec_EPOCH, + } + lockInfoHTLCBytes, _ := proto.Marshal(lockInfoHTLC) + lockInfo := &common.AssetLock{ + LockInfo: lockInfoHTLCBytes, + } + lockInfoBytes, _ := proto.Marshal(lockInfo) + bondAgreement := &common.AssetExchangeAgreement { + AssetType: bondType, + Id: bondId, + Locker: bondLocker, + Recipient: bondRecipient, + } + bondAgreementBytes, _ := proto.Marshal(bondAgreement) + bondAsset := sa.BondAsset { + Type: bondType, + ID: bondId, + Owner: bondLocker, + Issuer: bondIssuer, + FaceValue: bondFaceValue, + MaturityDate: bondMaturityDate, + } + bondAssetBytes, err := json.Marshal(bondAsset) + chaincodeStub.GetCreatorReturnsOnCall(0, []byte(getCreatorInContext("locker")), nil) + chaincodeStub.GetStateReturnsOnCall(4, bondAssetBytes, nil) + chaincodeStub.InvokeChaincodeReturnsOnCall(0, shim.Success([]byte("false"))) + chaincodeStub.InvokeChaincodeReturnsOnCall(1, shim.Success([]byte(bondContractId))) + bondContractId, err = sc.LockAsset(ctx, base64.StdEncoding.EncodeToString(bondAgreementBytes), base64.StdEncoding.EncodeToString(lockInfoBytes)) + require.NoError(t, err) + require.NotEmpty(t, bondContractId) + + + // Lock token asset in network2 by Bob for Alice + fmt.Println("*** Lock token asset in network2 by Bob ***") + tokensContractId := "tokens-contract" + tokensAgreement := &common.FungibleAssetExchangeAgreement { + AssetType: tokenType, + NumUnits: numTokens, + Locker: tokensLocker, + Recipient: tokensRecipient, + } + tokensAgreementBytes, _ := proto.Marshal(tokensAgreement) + chaincodeStub.GetCreatorReturnsOnCall(1, []byte(getCreatorInContext("recipient")), nil) + tokenAssetType = sa.TokenAssetType { + Issuer: tokenIssuer, + Value: tokenValue, + } + tokenAssetTypeBytes, _ = json.Marshal(tokenAssetType) + chaincodeStub.GetStateReturnsOnCall(5, tokenAssetTypeBytes, nil) + walletMap = make(map[string]uint64) + walletMap[tokenType] = numTokens + tokensWallet = &sa.TokenWallet{WalletMap: walletMap} + tokensWalletBytes, _ = json.Marshal(tokensWallet) + chaincodeStub.GetStateReturnsOnCall(6, tokensWalletBytes, nil) + chaincodeStub.InvokeChaincodeReturnsOnCall(2, shim.Success([]byte(tokensContractId))) + chaincodeStub.GetCreatorReturnsOnCall(2, []byte(getCreatorInContext("recipient")), nil) + chaincodeStub.GetStateReturnsOnCall(7, tokenAssetTypeBytes, nil) + chaincodeStub.GetStateReturnsOnCall(8, tokensWalletBytes, nil) + tokensContractId, err = sc.LockFungibleAsset(ctx, base64.StdEncoding.EncodeToString(tokensAgreementBytes), base64.StdEncoding.EncodeToString(lockInfoBytes)) + require.NoError(t, err) + require.NotEmpty(t, tokensContractId) + + + // Claim token asset in network2 by Alice + fmt.Println("*** Claim token asset in network2 by Alice ***") + preimageBase64 := base64.StdEncoding.EncodeToString([]byte(preimage)) + claimInfoHTLC := &common.AssetClaimHTLC { + HashPreimageBase64: []byte(preimageBase64), + } + claimInfoHTLCBytes, _ := proto.Marshal(claimInfoHTLC) + claimInfo := &common.AssetClaim{ + ClaimInfo: claimInfoHTLCBytes, + LockMechanism: common.LockMechanism_HTLC, + } + claimInfoBytes, _ := proto.Marshal(claimInfo) + chaincodeStub.InvokeChaincodeReturnsOnCall(3, shim.Success(nil)) + chaincodeStub.GetCreatorReturnsOnCall(3, []byte(getCreatorInContext("locker")), nil) + chaincodeStub.GetCreatorReturnsOnCall(4, []byte(getCreatorInContext("locker")), nil) + tokenAssetType = sa.TokenAssetType { + Issuer: tokenIssuer, + Value: tokenValue, + } + tokenAssetTypeBytes, _ = json.Marshal(tokenAssetType) + contractedTokenAsset := ContractedFungibleAsset{ + Type: tokenType, + NumUnits: numTokens, + } + + contractedTokenAssetBytes, _ := json.Marshal(contractedTokenAsset) + chaincodeStub.GetStateReturnsOnCall(9, tokenAssetTypeBytes, nil) + chaincodeStub.GetStateReturnsOnCall(10, contractedTokenAssetBytes, nil) + chaincodeStub.GetStateReturnsOnCall(11, nil, nil) + _, err = sc.ClaimFungibleAsset(ctx, base64.StdEncoding.EncodeToString(tokensAgreementBytes), base64.StdEncoding.EncodeToString(claimInfoBytes)) + require.NoError(t, err) + + + // Claim bond asset in network1 by Bob + fmt.Println("*** Claim bond asset in network1 by Bob ***") + chaincodeStub.InvokeChaincodeReturnsOnCall(4, shim.Success(nil)) + chaincodeStub.InvokeChaincodeReturnsOnCall(5, shim.Success([]byte("true"))) + chaincodeStub.InvokeChaincodeReturnsOnCall(6, shim.Success([]byte("true"))) + chaincodeStub.GetCreatorReturnsOnCall(5, []byte(getCreatorInContext("recipient")), nil) + chaincodeStub.GetStateReturnsOnCall(12, bondAssetBytes, nil) + chaincodeStub.GetStateReturnsOnCall(13, []byte(bondContractId), nil) + _, err = sc.ClaimAsset(ctx, base64.StdEncoding.EncodeToString(bondAgreementBytes), base64.StdEncoding.EncodeToString(claimInfoBytes)) + require.NoError(t, err) + +} diff --git a/weaver/samples/fabric/satpsimpleasset/bondasset.go b/weaver/samples/fabric/satpsimpleasset/bondasset.go new file mode 100644 index 0000000000..e5cb7cbf1f --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/bondasset.go @@ -0,0 +1,327 @@ +package main + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "time" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/cacti/weaver/common/protos-go/v2/common" + "github.com/hyperledger/fabric-contract-api-go/contractapi" +) + + +type BondAsset struct { + Type string `json:"type"` + ID string `json:"id"` + Owner string `json:"owner"` + Issuer string `json:"issuer"` + FaceValue int `json:"facevalue"` + MaturityDate time.Time `json:"maturitydate"` +} + +func getBondAssetKey(assetType string, assetId string) string { + return assetType + assetId +} + +func getBondAsset(ctx contractapi.TransactionContextInterface, assetType, id string) (*BondAsset, error) { + assetJSON, err := ctx.GetStub().GetState(getBondAssetKey(assetType, id)) + if err != nil { + return nil, fmt.Errorf("failed to read asset record from world state: %v", err) + } + if assetJSON == nil { + return nil, fmt.Errorf("the asset %s does not exist", id) + } + + var asset BondAsset + err = json.Unmarshal(assetJSON, &asset) + if err != nil { + return nil, err + } + return &asset, nil +} + +// InitBondAssetLedger adds a base set of assets to the ledger +func (s *SmartContract) InitBondAssetLedger(ctx contractapi.TransactionContextInterface) error { + assets := []BondAsset{ + {Type: "t1", ID: "a01", Issuer: "Treasury" , Owner: "", FaceValue: 300, + MaturityDate: time.Date(2022, time.April, 1, 12, 0, 0, 0, time.UTC)}, + {Type: "t1", ID: "a02", Issuer: "Treasury" , Owner: "", FaceValue: 400, + MaturityDate: time.Date(2022, time.July, 1, 12, 0, 0, 0, time.UTC)}, + } + + for _, asset := range assets { + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + err = ctx.GetStub().PutState(getBondAssetKey(asset.Type, asset.ID), assetJSON) + if err != nil { + return fmt.Errorf("failed to put to world state. %v", err) + } + } + + return nil +} + +// CreateAsset issues a new asset to the world state with given details. +func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, assetType, id, owner, issuer string, faceValue int, maturityDate string) error { + if assetType == "" { + return fmt.Errorf("Asset type cannot be blank") + } + if id == "" { + return fmt.Errorf("Asset ID cannot be blank") + } + if owner == "" && issuer == "" { + return fmt.Errorf("Asset Owner and Issuer cannot both be blank") + } + exists, err := s.AssetExists(ctx, assetType, id) + if err != nil { + return err + } + if exists { + return fmt.Errorf("the asset %s already exists", id) + } + + md_time, err := time.Parse(time.RFC822, maturityDate) + if err != nil { + return fmt.Errorf("maturity date provided is not in correct format, please use this format: %s", time.RFC822) + } + + if md_time.Before(time.Now()) { + return fmt.Errorf("maturity date can not be in past.") + } + + asset := BondAsset{ + Type: assetType, + ID: id, + Owner: owner, + Issuer: issuer, + FaceValue: faceValue, + MaturityDate: md_time, + } + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// ReadAsset returns the asset stored in the world state with given id. +// This function is called with the parameter inUpdateOwnerContext value as false, except in the update-owner context +func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, assetType, id string) (*BondAsset, error) { + asset, err := getBondAsset(ctx, assetType, id) + if err != nil { + return nil, err + } + if !checkAccessToAsset(s, ctx, asset) { + return nil, fmt.Errorf("cannot access Bond Asset %s", id) + } + return asset, nil +} + +// DeleteAsset deletes an given asset from the world state. +func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, assetType, id string) error { + + // Read the asset (which internally check access) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + return ctx.GetStub().DelState(getBondAssetKey(asset.Type, asset.ID)) +} + + +// isCallerAssetOwner returns true only if the invoker of the transaction is also the asset owner +func isCallerAssetOwner(ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + caller, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + fmt.Println(err.Error()) + return false + } + return (asset.Owner == caller) +} + +// isBondAssetLocked returns true only if the asset is presently locked +func isBondAssetLocked(s *SmartContract, ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + bondAssetAgreement := &common.AssetExchangeAgreement{ + AssetType: asset.Type, + Id: asset.ID, + Recipient: "*", + Locker: asset.Owner, + } + bondAssetAgreementProtoSerialized, err := proto.Marshal(bondAssetAgreement) + if err != nil { + fmt.Println(err.Error()) + return false + } + bondAssetAgreementProto64 := base64.StdEncoding.EncodeToString(bondAssetAgreementProtoSerialized) + locked, err := s.IsAssetLocked(ctx, bondAssetAgreementProto64) + if err != nil { + fmt.Println(err.Error()) + return false + } + return locked +} + +// isBondAssetLockedForMe returns true only if the asset is presently locked for me +func isBondAssetLockedForMe(s *SmartContract, ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + bondAssetAgreement := &common.AssetExchangeAgreement{ + AssetType: asset.Type, + Id: asset.ID, + Recipient: "", + Locker: asset.Owner, + } + bondAssetAgreementProtoSerialized, err := proto.Marshal(bondAssetAgreement) + if err != nil { + fmt.Println(err.Error()) + return false + } + bondAssetAgreementProto64 := base64.StdEncoding.EncodeToString(bondAssetAgreementProtoSerialized) + locked, err := s.IsAssetLocked(ctx, bondAssetAgreementProto64) + if err != nil { + fmt.Println(err.Error()) + return false + } + return locked +} + +// checkAccessToAsset checks several conditions under which an asset can be put on hold (i.e., not available for regular business operation) +func checkAccessToAsset(s *SmartContract, ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + // Ensure that the client is the owner of the asset + if !isCallerAssetOwner(ctx, asset) { + fmt.Printf("Illegal update: caller is not owner of asset %s\n", asset.ID) + return false + } + + // Ensure that the asset is not locked + if isBondAssetLocked(s, ctx, asset) { + fmt.Printf("Cannot update attributes of locked asset %s\n", asset.ID) + return false + } + + return true +} + +// AssetExists returns true when asset with given ID exists in world state +func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, assetType, id string) (bool, error) { + assetJSON, err := ctx.GetStub().GetState(getBondAssetKey(assetType, id)) + if err != nil { + return false, fmt.Errorf("failed to read asset record from world state: %v", err) + } + + return assetJSON != nil, nil +} + +// IsAssetReleased returns true if asset maturity date elapses +func (s *SmartContract) IsAssetReleased(ctx contractapi.TransactionContextInterface, assetType, id string) (bool, error) { + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return false, err + } + currDate := time.Now() + if (currDate.After(asset.MaturityDate)) { + return true, nil + } + + return false, nil +} + +// UpdateOwner sets the owner of an asset to a new owner. +func (s *SmartContract) UpdateOwner(ctx contractapi.TransactionContextInterface, assetType, id string, newOwner string) error { + // Read asset (which internally checks access if it is free to modified) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + + asset.Owner = newOwner + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// UpdateMaturityDate sets the maturity date of the asset to an updated date as passed in the parameters. +func (s *SmartContract) UpdateMaturityDate(ctx contractapi.TransactionContextInterface, assetType, id string, newMaturityDate time.Time) error { + // Read asset (which internally checks access if it is free to modified) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + + asset.MaturityDate = newMaturityDate + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// UpdateFaceValue sets the face value of an asset to the new value passed. +func (s *SmartContract) UpdateFaceValue(ctx contractapi.TransactionContextInterface, assetType, id string, newFaceValue int) error { + // Read asset (which internally checks access if it is free to modified) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + + asset.FaceValue = newFaceValue + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// GetMyAssets returns the assets owner by the caller +func (s *SmartContract) GetMyAssets(ctx contractapi.TransactionContextInterface) ([]*BondAsset, error) { + assets, err := s.GetAllAssets(ctx) + if err != nil { + return nil, err + } + + var myassets []*BondAsset + + for _, asset := range assets { + if checkAccessToAsset(s, ctx, asset) { + myassets = append(myassets, asset) + } + } + return myassets, nil +} + +// GetAllAssets returns all assets found in world state +func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*BondAsset, error) { + // range query with empty string for startKey and endKey does an + // open-ended query of all assets in the chaincode namespace. + resultsIterator, err := ctx.GetStub().GetStateByRange("", "") + if err != nil { + return nil, err + } + defer resultsIterator.Close() + + var assets []*BondAsset + for resultsIterator.HasNext() { + queryResponse, err := resultsIterator.Next() + if err != nil { + return nil, err + } + + var asset BondAsset + err = json.Unmarshal(queryResponse.Value, &asset) + if err != nil { + return nil, err + } + assets = append(assets, &asset) + } + + return assets, nil +} diff --git a/weaver/samples/fabric/satpsimpleasset/bondasset_test.go b/weaver/samples/fabric/satpsimpleasset/bondasset_test.go new file mode 100644 index 0000000000..b43170e23a --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/bondasset_test.go @@ -0,0 +1,242 @@ +package main_test + +import ( + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/hyperledger/fabric-protos-go/ledger/queryresult" + sa "github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset" + "github.com/stretchr/testify/require" + wtest "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils" + wtestmocks "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils/mocks" +) + +const ( + defaultAssetType = "BearerBonds" + defaultAssetId = "asset1" + defaultAssetOwner = "Alice" + defaultAssetIssuer = "Treasury" +) + +func TestInitBondAssetLedger(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + err := simpleAsset.InitBondAssetLedger(transactionContext) + require.NoError(t, err) + + chaincodeStub.PutStateReturns(fmt.Errorf("failed inserting key")) + err = simpleAsset.InitBondAssetLedger(transactionContext) + require.EqualError(t, err, "failed to put to world state. failed inserting key") +} + +func TestCreateAsset(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + err := simpleAsset.CreateAsset(transactionContext, "", "", "", "", 0, "02 Jan 26 15:04 MST") + require.Error(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, "", "", "", 0, "02 Jan 26 15:04 MST") + require.Error(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, "", "", 0, "02 Jan 26 15:04 MST") + require.Error(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "02 Jan 26 15:04 MST") + require.NoError(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, "", defaultAssetIssuer, 0, "02 Jan 26 15:04 MST") + require.NoError(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "02 Jan 06 15:04 MST") + require.EqualError(t, err, "maturity date can not be in past.") + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "") + require.EqualError(t, err, "maturity date provided is not in correct format, please use this format: 02 Jan 06 15:04 MST") + + chaincodeStub.GetStateReturns([]byte{}, nil) + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "") + require.EqualError(t, err, "the asset asset1 already exists") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestReadAsset(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + expectedAsset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + asset, err := simpleAsset.ReadAsset(transactionContext, "", "") + require.NoError(t, err) + require.Equal(t, expectedAsset, asset) + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + _, err = simpleAsset.ReadAsset(transactionContext, "", "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") + + chaincodeStub.GetStateReturns(nil, nil) + asset, err = simpleAsset.ReadAsset(transactionContext, "", "asset1") + require.EqualError(t, err, "the asset asset1 does not exist") + require.Nil(t, asset) +} + +func TestUpdateFaceValue(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + expectedAsset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleAsset.UpdateFaceValue(transactionContext, "", "", 0) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, nil) + err = simpleAsset.UpdateFaceValue(transactionContext, "", "asset1", 0) + require.EqualError(t, err, "the asset asset1 does not exist") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.UpdateFaceValue(transactionContext, "", "asset1", 0) + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestUpdateMaturityDate(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + expectedAsset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleAsset.UpdateMaturityDate(transactionContext, "", "", time.Now()) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, nil) + err = simpleAsset.UpdateMaturityDate(transactionContext, "", "asset1", time.Now()) + require.EqualError(t, err, "the asset asset1 does not exist") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.UpdateMaturityDate(transactionContext, "", "asset1", time.Now()) + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestDeleteAsset(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + asset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(nil) + err = simpleAsset.DeleteAsset(transactionContext, "", "") + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, nil) + err = simpleAsset.DeleteAsset(transactionContext, "", "asset1") + require.EqualError(t, err, "the asset asset1 does not exist") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.DeleteAsset(transactionContext, "", "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestUpdateOwner(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + asset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleAsset.UpdateOwner(transactionContext, "", "", "") + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.UpdateOwner(transactionContext, "", "", "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestGetMyAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + iterator := &wtestmocks.StateQueryIterator{} + + asset := &sa.BondAsset{ID: "asset1", Owner: getTestTxCreatorECertBase64()} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + iterator.HasNextReturnsOnCall(0, true) + iterator.HasNextReturnsOnCall(1, false) + iterator.NextReturns(&queryresult.KV{Value: bytes}, nil) + + chaincodeStub.GetCreatorReturns([]byte(getCreator()), nil) + + chaincodeStub.GetStateByRangeReturns(iterator, nil) + assets, err := simpleAsset.GetAllAssets(transactionContext) + require.NoError(t, err) + require.Equal(t, []*sa.BondAsset{asset}, assets) + + iterator.HasNextReturns(true) + iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving next item") + require.Nil(t, assets) + + chaincodeStub.GetStateByRangeReturns(nil, fmt.Errorf("failed retrieving all assets")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving all assets") + require.Nil(t, assets) +} + +func TestGetAllAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + iterator := &wtestmocks.StateQueryIterator{} + + asset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + iterator.HasNextReturnsOnCall(0, true) + iterator.HasNextReturnsOnCall(1, false) + iterator.NextReturns(&queryresult.KV{Value: bytes}, nil) + + chaincodeStub.GetStateByRangeReturns(iterator, nil) + assets, err := simpleAsset.GetAllAssets(transactionContext) + require.NoError(t, err) + require.Equal(t, []*sa.BondAsset{asset}, assets) + + iterator.HasNextReturns(true) + iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving next item") + require.Nil(t, assets) + + chaincodeStub.GetStateByRangeReturns(nil, fmt.Errorf("failed retrieving all assets")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving all assets") + require.Nil(t, assets) +} diff --git a/weaver/samples/fabric/satpsimpleasset/go.mod b/weaver/samples/fabric/satpsimpleasset/go.mod new file mode 100644 index 0000000000..a7d64f87cf --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/go.mod @@ -0,0 +1,42 @@ +module github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset + +go 1.20 + +require ( + github.com/golang/protobuf v1.5.3 + github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 + github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 + github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils v0.0.0-20210920170720-5d5bf2a54081 + github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a + github.com/hyperledger/fabric-contract-api-go v1.2.1 + github.com/hyperledger/fabric-protos-go v0.3.0 + github.com/sirupsen/logrus v1.9.0 + github.com/stretchr/testify v1.8.2 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/spec v0.20.8 // indirect + github.com/go-openapi/swag v0.21.1 // indirect + github.com/gobuffalo/envy v1.10.1 // indirect + github.com/gobuffalo/packd v1.0.1 // indirect + github.com/gobuffalo/packr v1.30.1 // indirect + github.com/joho/godotenv v1.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.8.1 // indirect + 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.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect + google.golang.org/grpc v1.54.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/weaver/samples/fabric/satpsimpleasset/go.sum b/weaver/samples/fabric/satpsimpleasset/go.sum new file mode 100644 index 0000000000..23646b5a4f --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/go.sum @@ -0,0 +1,157 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU= +github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.10.1 h1:ppDLoXv2feQ5nus4IcgtyMdHQkKng2lhJCIm33cblM0= +github.com/gobuffalo/envy v1.10.1/go.mod h1:AWx4++KnNOW3JOeEvhSaq+mvgAvnMYOY1XSIin4Mago= +github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= +github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY= +github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= +github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= +github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a h1:HwSCxEeiBthwcazcAykGATQ36oG9M+HEQvGLvB7aLvA= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a/go.mod h1:TDSu9gxURldEnaGSFbH1eMlfSQBWQcMQfnDBcpQv5lU= +github.com/hyperledger/fabric-contract-api-go v1.2.1 h1:Ww9cKH/qHl5s6WqF+Ts5ju5eaBxC/awB/BJE+rOsEkM= +github.com/hyperledger/fabric-contract-api-go v1.2.1/go.mod h1:BhWve0gz1iH+Xc+cO3rmeIZI7YaTWOQodka9CgeUOgo= +github.com/hyperledger/fabric-protos-go v0.3.0 h1:MXxy44WTMENOh5TI8+PCK2x6pMj47Go2vFRKDHB2PZs= +github.com/hyperledger/fabric-protos-go v0.3.0/go.mod h1:WWnyWP40P2roPmmvxsUXSvVI/CF6vwY1K1UFidnKBys= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +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/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.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +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.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +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 v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +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-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha-prerelease h1:MpVTzM8FvQ+2Qij/0DH0cGy2NoC1S5gD5c40HuEQlsI= +github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha-prerelease/go.mod h1:3DmkYfZoc+TtcAgF3kX6CmQDNKKKCHgbaoQuYu/3ayc= +github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha-prerelease h1:kks9cM6vS3raV6Ag6FTddFdy11LvUAc6oYHVRUU95ts= +github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha-prerelease/go.mod h1:jzOMrtkM1AwBUgfedRs7FkcZpl1g/eRe1wnQO9GEoio= +github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 h1:r7RknfMWs/riL4saBB31iWfRaP03AJuo19K2ettHP3E= +github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1/go.mod h1:3DmkYfZoc+TtcAgF3kX6CmQDNKKKCHgbaoQuYu/3ayc= +github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 h1:ssYji+cWvfnPYRBQyx7J/aBVTaVdHbb2gOQOLfVZRCw= +github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1/go.mod h1:zei2BRZv+Ln+3o5yr7K900LRpEDCiado8px0hoGuuco= diff --git a/weaver/samples/fabric/satpsimpleasset/helper.go b/weaver/samples/fabric/satpsimpleasset/helper.go new file mode 100644 index 0000000000..efca833cc7 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/helper.go @@ -0,0 +1,53 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// helper contains miscelaneous helper functions used throughout the code +package main + +import ( + "fmt" + "errors" + "encoding/base64" + "bytes" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric-contract-api-go/contractapi" + mspProtobuf "github.com/hyperledger/fabric-protos-go/msp" + log "github.com/sirupsen/logrus" +) + +// functions to log and return errors +func logThenErrorf(format string, args ...interface{}) error { + errorMsg := fmt.Sprintf(format, args...) + log.Error(errorMsg) + return errors.New(errorMsg) +} + +func getECertOfTxCreatorBase64(ctx contractapi.TransactionContextInterface) (string, error) { + + txCreatorBytes, err := ctx.GetStub().GetCreator() + if err != nil { + return "", fmt.Errorf("unable to get the transaction creator information: %+v", err) + } + + serializedIdentity := &mspProtobuf.SerializedIdentity{} + err = proto.Unmarshal(txCreatorBytes, serializedIdentity) + if err != nil { + return "", fmt.Errorf("getECertOfTxCreatorBase64: unmarshal error: %+v", err) + } + + eCertBytesBase64 := base64.StdEncoding.EncodeToString(serializedIdentity.IdBytes) + + return eCertBytesBase64, nil +} + +func createKeyValuePairs(m map[string]uint64) string { + b := new(bytes.Buffer) + for key, value := range m { + fmt.Fprintf(b, "%s=\"%d\"\n", key, value) + } + return b.String() +} diff --git a/weaver/samples/fabric/satpsimpleasset/main.go b/weaver/samples/fabric/satpsimpleasset/main.go new file mode 100644 index 0000000000..0b8c5b9d71 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/main.go @@ -0,0 +1,59 @@ +package main + +import ( + "fmt" + "os" + + "github.com/hyperledger/fabric-chaincode-go/shim" + "github.com/hyperledger/fabric-contract-api-go/contractapi" + am "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2" +) + +// SmartContract provides functions for managing an BondAsset and TokenAsset +type SmartContract struct { + contractapi.Contract + amc am.AssetManagementContract +} + +func (s *SmartContract) ConfigureInterop(interopChaincodeId string) { + s.amc.Configure(interopChaincodeId) +} + +func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface, ccType string, interopChaincodeId string) error { + s.ConfigureInterop(interopChaincodeId) + if ccType == "Bond" { + return s.InitBondAssetLedger(ctx) + } else if ccType == "Token" { + return s.InitTokenAssetLedger(ctx) + } + return fmt.Errorf("only Bond and Token are accepted as ccType.") +} + +func main() { + chaincode, err := contractapi.NewChaincode(new(SmartContract)) + + if err != nil { + fmt.Printf("Error creating chaincode: %s", err.Error()) + return + } + + _, ok := os.LookupEnv("EXTERNAL_SERVICE") + if ok { + server := &shim.ChaincodeServer{ + CCID: os.Getenv("CHAINCODE_CCID"), + Address: os.Getenv("CHAINCODE_ADDRESS"), + CC: chaincode, + TLSProps: shim.TLSProperties{ + Disabled: true, + }, + } + // Start the chaincode external server + err = server.Start() + } else { + err = chaincode.Start() + } + if err != nil { + fmt.Printf("Error starting chaincode: %s", err.Error()) + } + +} diff --git a/weaver/samples/fabric/satpsimpleasset/tokenasset.go b/weaver/samples/fabric/satpsimpleasset/tokenasset.go new file mode 100644 index 0000000000..972d90399a --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/tokenasset.go @@ -0,0 +1,316 @@ +package main + +import ( + "encoding/json" + "fmt" + + "github.com/hyperledger/fabric-contract-api-go/contractapi" +) + +type TokenAssetType struct { + Issuer string `json:"issuer"` + Value int `json:"value"` +} +type TokenWallet struct { + WalletMap map[string]uint64 `json:"walletlist"` +} + + +// InitTokenAssetLedger adds a base set of assets to the ledger +func (s *SmartContract) InitTokenAssetLedger(ctx contractapi.TransactionContextInterface) error { + _, err := s.CreateTokenAssetType(ctx, "token1", "CentralBank", 1) + if err != nil { + return err + } + return err +} + +// CreateTokenAssetType issues a new token asset type to the world state with given details. +func (s *SmartContract) CreateTokenAssetType(ctx contractapi.TransactionContextInterface, tokenAssetType string, issuer string, value int) (bool, error) { + if tokenAssetType == "" { + return false, fmt.Errorf("Token asset type cannot be blank") + } + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return false, err + } + if exists { + return false, fmt.Errorf("the token asset type %s already exists.", tokenAssetType) + } + + asset := TokenAssetType{ + Issuer: issuer, + Value: value, + } + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, err + } + id := getTokenAssetTypeId(tokenAssetType) + err = ctx.GetStub().PutState(id, assetJSON) + + if err != nil { + return false, fmt.Errorf("failed to create token asset type %s. %v", tokenAssetType, err) + } + return true, nil +} + +// ReadTokenAssetType returns the token asset type stored in the world state with given type. +func (s *SmartContract) ReadTokenAssetType(ctx contractapi.TransactionContextInterface, tokenAssetType string) (*TokenAssetType, error) { + id := getTokenAssetTypeId(tokenAssetType) + assetJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return nil, fmt.Errorf("failed to read token asset type %s: %v", tokenAssetType, err) + } + if assetJSON == nil { + return nil, fmt.Errorf("the token asset type %s does not exist.", tokenAssetType) + } + + var fat TokenAssetType + err = json.Unmarshal(assetJSON, &fat) + if err != nil { + return nil, err + } + + return &fat, nil +} + +// DeleteTokenAssetType deletes an given token asset type from the world state. +func (s *SmartContract) DeleteTokenAssetType(ctx contractapi.TransactionContextInterface, tokenAssetType string) error { + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the token asset type %s does not exist.", tokenAssetType) + } + + id := getTokenAssetTypeId(tokenAssetType) + err = ctx.GetStub().DelState(id) + if err != nil { + return fmt.Errorf("failed to delete token asset type %s: %v", tokenAssetType, err) + } + return nil +} + +// TokenAssetTypeExists returns true when token asset type with given ID exists in world state +func (s *SmartContract) TokenAssetTypeExists(ctx contractapi.TransactionContextInterface, tokenAssetType string) (bool, error) { + id := getTokenAssetTypeId(tokenAssetType) + assetJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return false, fmt.Errorf("failed to read from world state: %v", err) + } + + return assetJSON != nil, nil +} + +// IssueTokenAssets issues new token assets to an owner. +func (s *SmartContract) IssueTokenAssets(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, owner string) error { + if owner == "" { + return fmt.Errorf("Owner cannot be blank") + } + + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("cannot issue: the token asset type %s does not exist", tokenAssetType) + } + + id := getWalletId(owner) + return addTokenAssetsHelper(ctx, tokenAssetType, numUnits, id) +} + +// DeleteTokenAssets burns the token assets from an owner. +func (s *SmartContract) DeleteTokenAssets(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64) error { + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return err + } + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the token asset type %s does not exist", tokenAssetType) + } + + id := getWalletId(owner) + return subTokenAssetsHelper(ctx, tokenAssetType, numUnits, id) +} + +// TransferTokenAssets transfers the token assets from client's account to newOwner +func (s *SmartContract) TransferTokenAssets(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, newOwner string) error { + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the token asset type %s does not exist", tokenAssetType) + } + + if newOwner == "" { + return fmt.Errorf("New owner cannot be blank") + } + + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return err + } + + ownerId := getWalletId(owner) + newOwnerId := getWalletId(newOwner) + + err = subTokenAssetsHelper(ctx, tokenAssetType, numUnits, ownerId) + if err != nil { + return err + } + return addTokenAssetsHelper(ctx, tokenAssetType, numUnits, newOwnerId) +} + +// GetBalance returns the amount of given token asset type owned by an owner. +func (s *SmartContract) GetBalance(ctx contractapi.TransactionContextInterface, tokenAssetType string, owner string) (uint64, error) { + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return 0, err + } + if !exists { + return 0, fmt.Errorf("the token asset type %s does not exist", tokenAssetType) + } + + id := getWalletId(owner) + walletJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return 0, fmt.Errorf("failed to read owner's wallet from world state: %v", err) + } + if walletJSON == nil { + return 0, fmt.Errorf("owner does not have a wallet") + } + + var wallet TokenWallet + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return 0, err + } + balance := wallet.WalletMap[tokenAssetType] + return balance, nil +} + +// GetMyWallet returns the available amount for each token asset type owned by an owner. +func (s *SmartContract) GetMyWallet(ctx contractapi.TransactionContextInterface) (string, error) { + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return "", err + } + + id := getWalletId(owner) + walletJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return "", fmt.Errorf("failed to read owner's wallet from world state: %v", err) + } + if walletJSON == nil { + return "", fmt.Errorf("owner does not have a wallet") + } + + var wallet TokenWallet + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return "", err + } + return createKeyValuePairs(wallet.WalletMap), nil +} + +// Checks if owner has some given amount of token asset +func (s *SmartContract) TokenAssetsExist(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64) (bool, error) { + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, err + } + balance, err := s.GetBalance(ctx, tokenAssetType, owner) + if err != nil { + return false, err + } + return balance >= numUnits, nil +} + +// Helper Functions for token asset +func addTokenAssetsHelper(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, id string) error { + walletJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return logThenErrorf("failed to retrieve entry from ledger: %+v", err) + } + var wallet TokenWallet + if walletJSON != nil { + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return err + } + balance := wallet.WalletMap[tokenAssetType] + wallet.WalletMap[tokenAssetType] = balance + numUnits + } else { + walletMap := make(map[string]uint64) + walletMap[tokenAssetType] = numUnits + wallet = TokenWallet{ + WalletMap: walletMap, + } + } + + walletNewJSON, err := json.Marshal(wallet) + if err != nil { + return err + } + return ctx.GetStub().PutState(id, walletNewJSON) +} + +func subTokenAssetsHelper(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, id string) error { + walletJSON, err := ctx.GetStub().GetState(id) + var wallet TokenWallet + if err != nil { + return err + } + if walletJSON == nil { + return fmt.Errorf("owner does not have a wallet") + } + + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return err + } + + // Check if owner has sufficient amount of given type to delete + _, exists := wallet.WalletMap[tokenAssetType] + if !exists { + return fmt.Errorf("the owner does not possess any units of the token asset type %s", tokenAssetType) + } + if wallet.WalletMap[tokenAssetType] < numUnits { + return fmt.Errorf("the owner does not possess enough units of the token asset type %s", tokenAssetType) + } + + // Subtract after all checks + wallet.WalletMap[tokenAssetType] -= numUnits + + // Delete token asset type from map if num of units becomes zero + if wallet.WalletMap[tokenAssetType] == 0 { + delete(wallet.WalletMap, tokenAssetType) + } + + if len(wallet.WalletMap) == 0 { + // Delete the entry from State if wallet becomes empty + return ctx.GetStub().DelState(id) + } else { + // Update the new wallet object otherwise + walletNewJSON, err := json.Marshal(wallet) + if err != nil { + return err + } + return ctx.GetStub().PutState(id, walletNewJSON) + } +} + +func getTokenAssetTypeId(tokenAssetType string) string { + return "FAT_" + tokenAssetType +} +func getWalletId(owner string) string { + return "W_" + owner +} diff --git a/weaver/samples/fabric/satpsimpleasset/tokenasset_test.go b/weaver/samples/fabric/satpsimpleasset/tokenasset_test.go new file mode 100644 index 0000000000..facbfb393f --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/tokenasset_test.go @@ -0,0 +1,326 @@ +package main_test + +import ( + "encoding/json" + "fmt" + "testing" + "encoding/base64" + "bytes" + + "github.com/golang/protobuf/proto" + mspProtobuf "github.com/hyperledger/fabric-protos-go/msp" + sa "github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset" + "github.com/stretchr/testify/require" + wtest "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils" +) + +func TestInitTokenAssetLedger(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + err := simpleToken.InitTokenAssetLedger(transactionContext) + require.NoError(t, err) + + chaincodeStub.PutStateReturns(fmt.Errorf("failed inserting key")) + err = simpleToken.InitTokenAssetLedger(transactionContext) + require.EqualError(t, err, "failed to create token asset type token1. failed inserting key") +} + +func TestCreateTokenAssetType(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + // Should fail if token asset type is empty + res, err := simpleToken.CreateTokenAssetType(transactionContext, "", "", 0) + require.Error(t, err) + + // Successful Case + res, err = simpleToken.CreateTokenAssetType(transactionContext, "sometokentype", "", 0) + require.NoError(t, err) + require.Equal(t, res, true) + + // Check if tokenAssetType already exists + chaincodeStub.GetStateReturns([]byte{}, nil) + res, err = simpleToken.CreateTokenAssetType(transactionContext, "token1", "", 0) + require.EqualError(t, err, "the token asset type token1 already exists.") + require.Equal(t, res, false) + + // Check if PutState fails + chaincodeStub.GetStateReturns(nil, nil) + chaincodeStub.PutStateReturns(fmt.Errorf("failed to put state")) + res, err = simpleToken.CreateTokenAssetType(transactionContext, "token1", "", 0) + require.EqualError(t, err, "failed to create token asset type token1. failed to put state") + require.Equal(t, res, false) + + // Check if GetState fails + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + res, err = simpleToken.CreateTokenAssetType(transactionContext, "token1", "", 0) + require.EqualError(t, err, "failed to read from world state: unable to retrieve asset") + require.Equal(t, res, false) +} + +func TestReadTokenAssetType(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + expectedAsset := &sa.TokenAssetType{Issuer: "CentralBank", Value: 10} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Successful Read + chaincodeStub.GetStateReturns(bytes, nil) + asset, err := simpleToken.ReadTokenAssetType(transactionContext, "") + require.NoError(t, err) + require.Equal(t, expectedAsset, asset) + + // GetState Fail case + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + _, err = simpleToken.ReadTokenAssetType(transactionContext, "") + require.EqualError(t, err, "failed to read token asset type : unable to retrieve asset") + + // token asset type does not exist + chaincodeStub.GetStateReturns(nil, nil) + asset, err = simpleToken.ReadTokenAssetType(transactionContext, "token1") + require.EqualError(t, err, "the token asset type token1 does not exist.") + require.Nil(t, asset) +} + +func TestDeleteTokenAssetType(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + chaincodeStub.DelStateReturns(nil) + err := simpleToken.DeleteTokenAssetType(transactionContext, "") + require.EqualError(t, err, "the token asset type does not exist.") + + bytes, err := json.Marshal(true) + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(fmt.Errorf("unable to retrieve asset")) + err = simpleToken.DeleteTokenAssetType(transactionContext, "token1") + require.EqualError(t, err, "failed to delete token asset type token1: unable to retrieve asset") + + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(nil) + err = simpleToken.DeleteTokenAssetType(transactionContext, "token1") + require.NoError(t, err) +} + +func TestIssueTokenAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Should fail of owner is blank + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "") + require.Error(t, err) + + // Checking succesful case + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "someowner") + require.NoError(t, err) + + // Check if writing state after issuing fails + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.PutStateReturns(fmt.Errorf("failed to put state")) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "someowner") + require.EqualError(t, err, "failed to put state") + + // Error check + chaincodeStub.GetStateReturns(nil, fmt.Errorf("failed to read state")) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "someowner") + require.EqualError(t, err, "failed to read from world state: failed to read state") + + // Check if given token asset type doesn't exist + chaincodeStub.GetStateReturns(nil, nil) + err = simpleToken.IssueTokenAssets(transactionContext, "token1", 0, "someowner") + require.EqualError(t, err, "cannot issue: the token asset type token1 does not exist") +} + +func TestDeleteTokenAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Successful delete case + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.DeleteTokenAssets(transactionContext, "token1", 2) + require.NoError(t, err) + + // Trying to delete more than owner hass + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.DeleteTokenAssets(transactionContext, "token1", 10) + require.EqualError(t, err, "the owner does not possess enough units of the token asset type token1") + + // Trying to delete token that owner doesn't possess + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.DeleteTokenAssets(transactionContext, "token2", 2) + require.EqualError(t, err, "the owner does not possess any units of the token asset type token2") + + // Error Check + chaincodeStub.GetStateReturns(nil, fmt.Errorf("Failed to read state")) + err = simpleToken.DeleteTokenAssets(transactionContext, "", 0) + require.EqualError(t, err, "failed to read from world state: Failed to read state") + + // check if it tries to delete wallet entry when wallet list is empty + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(fmt.Errorf("Failed to delete state")) + err = simpleToken.DeleteTokenAssets(transactionContext, "token1", 5) + require.EqualError(t, err, "Failed to delete state") + +} +func TestTransferTokenAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.TransferTokenAssets(transactionContext, "token1", 2, "") + require.Error(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.TransferTokenAssets(transactionContext, "token1", 2, "newowner") + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.TransferTokenAssets(transactionContext, "token1", 10, "newowner") + require.EqualError(t, err, "the owner does not possess enough units of the token asset type token1") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("Failed to read state")) + err = simpleToken.DeleteTokenAssets(transactionContext, "", 0) + require.EqualError(t, err, "failed to read from world state: Failed to read state") +} +func TestGetBalance(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Successful GetBalance case + chaincodeStub.GetStateReturnsOnCall(0, bytes, nil) + chaincodeStub.GetStateReturnsOnCall(1, bytes, nil) + bal, err := simpleToken.GetBalance(transactionContext, "token1", "") + require.NoError(t, err) + require.Equal(t, bal, uint64(5)) + + // GetState Fails + chaincodeStub.GetStateReturnsOnCall(2, nil, fmt.Errorf("Failed to read state")) + bal, err = simpleToken.GetBalance(transactionContext, "", "") + require.EqualError(t, err, "failed to read from world state: Failed to read state") + + chaincodeStub.GetStateReturnsOnCall(3, bytes, nil) + chaincodeStub.GetStateReturnsOnCall(4, nil, fmt.Errorf("Failed to read state")) + bal, err = simpleToken.GetBalance(transactionContext, "", "") + require.EqualError(t, err, "failed to read owner's wallet from world state: Failed to read state") +} + +func TestGetMyWallet(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedRes := createKeyValuePairs(walletMap) + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetCreatorReturns([]byte(getCreator()), nil) + + // Successful GetBalance case + chaincodeStub.GetStateReturnsOnCall(0, bytes, nil) + bal, err := simpleToken.GetMyWallet(transactionContext) + require.NoError(t, err) + require.Equal(t, bal, expectedRes) + + chaincodeStub.GetStateReturnsOnCall(1, nil, fmt.Errorf("Failed to read state")) + bal, err = simpleToken.GetMyWallet(transactionContext) + require.EqualError(t, err, "failed to read owner's wallet from world state: Failed to read state") + + // Owner doesn't have a wallet + chaincodeStub.GetStateReturnsOnCall(2, nil, nil) + bal, err = simpleToken.GetMyWallet(transactionContext) + require.EqualError(t, err, "owner does not have a wallet") +} + +func TestTokenAssetsExist(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Token Assets exist case + chaincodeStub.GetStateReturns(bytes, nil) + res, err := simpleToken.TokenAssetsExist(transactionContext, "token1", 4) + require.NoError(t, err) + require.Equal(t, res, true) + + // Token Assets doesn't exist case + chaincodeStub.GetStateReturns(bytes, nil) + res, err = simpleToken.TokenAssetsExist(transactionContext, "token1", 6) + require.NoError(t, err) + require.Equal(t, res, false) + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("Failed to read state")) + res, err = simpleToken.TokenAssetsExist(transactionContext, "", 0) + require.EqualError(t, err, "failed to read from world state: Failed to read state") + require.Equal(t, res, false) +} + +// function that supplies value that is to be returned by ctx.GetStub().GetCreator() +func getCreator() string { + serializedIdentity := &mspProtobuf.SerializedIdentity{} + eCertBytes, _ := base64.StdEncoding.DecodeString(getTestTxCreatorECertBase64()) + serializedIdentity.IdBytes = []byte(eCertBytes) + serializedIdentity.Mspid = "ca.org1.example.com" + serializedIdentityBytes, _ := proto.Marshal(serializedIdentity) + + return string(serializedIdentityBytes) +} + +// function that supplies the ECert in base64 for the transaction creator +func getTestTxCreatorECertBase64() string { + eCertBase64 := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNVVENDQWZpZ0F3SUJBZ0lSQU5qaWdnVHRhSERGRmtIaUI3VnhPN013Q2dZSUtvWkl6ajBFQXdJd2N6RUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdUQ2tOaGJHbG1iM0p1YVdFeEZqQVVCZ05WQkFjVERWTmhiaUJHY21GdVkybHpZMjh4R1RBWEJnTlZCQW9URUc5eVp6RXVaWGhoYlhCc1pTNWpiMjB4SERBYUJnTlZCQU1URTJOaExtOXlaekV1WlhoaGJYQnNaUzVqYjIwd0hoY05NVGt3TkRBeE1EZzBOVEF3V2hjTk1qa3dNekk1TURnME5UQXdXakJ6TVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNCTUtRMkZzYVdadmNtNXBZVEVXTUJRR0ExVUVCeE1OVTJGdUlFWnlZVzVqYVhOamJ6RVpNQmNHQTFVRUNoTVFiM0puTVM1bGVHRnRjR3hsTG1OdmJURWNNQm9HQTFVRUF4TVRZMkV1YjNKbk1TNWxlR0Z0Y0d4bExtTnZiVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCT2VlYTRCNlM5ZTlyLzZUWGZFZUFmZ3FrNVdpcHZZaEdveGg1ZEZuK1g0bTN2UXZTQlhuVFdLVzczZVNnS0lzUHc5dExDVytwZW9yVnMxMWdieXdiY0dqYlRCck1BNEdBMVVkRHdFQi93UUVBd0lCcGpBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFnWUlLd1lCQlFVSEF3RXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QXBCZ05WSFE0RUlnUWcxYzJHZmJTa3hUWkxIM2VzUFd3c2llVkU1QWhZNHNPQjVGOGEvaHM5WjhVd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ1JkZ1krNW9iMDNqVjJLSzFWdjZiZE5xM2NLWHc0cHhNVXY5MFZOc0tHdTBDSUE4Q0lMa3ZEZWg3NEFCRDB6QUNkbitBTkMyVVQ2Sk5UNnd6VHNLN3BYdUwKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==" + + return eCertBase64 +} + +func createKeyValuePairs(m map[string]uint64) string { + b := new(bytes.Buffer) + for key, value := range m { + fmt.Fprintf(b, "%s=\"%d\"\n", key, value) + } + return b.String() +} diff --git a/weaver/sdks/fabric/interoperation-node-sdk/index.js b/weaver/sdks/fabric/interoperation-node-sdk/index.js index 8b8563d73b..670914a2b8 100644 --- a/weaver/sdks/fabric/interoperation-node-sdk/index.js +++ b/weaver/sdks/fabric/interoperation-node-sdk/index.js @@ -25,6 +25,7 @@ module.exports.RelayHelper = require("./src/Relay.js"); module.exports.InteroperableHelper = require("./src/InteroperableHelper.js"); module.exports.AssetManager = require("./src/AssetManager.js"); +module.exports.SatpAssetManager = require("./src/SatpAssetManager.js"); module.exports.HashFunctions = require("./src/HashFunctions.js"); module.exports.EventsManager = require("./src/EventsManager.js"); module.exports.MembershipManager = require("./src/MembershipManager.js"); diff --git a/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts b/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts index d18813ecb3..772fb10e2e 100644 --- a/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts +++ b/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts @@ -393,6 +393,64 @@ const claimFungibleAssetInHTLC = async ( return result; }; +const assignAsset = async ( + contract: Contract, + assetType: string, + assetID: string, + lockerECert: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, "", lockerECert); + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("AssignAsset") + const ccArgs = [assetExchangeAgreementStr, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`AssignAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + /** * Rollback step of a Hashed Time Lock Contract * - Reclaim a unique asset instance @@ -1031,6 +1089,7 @@ export { claimAssetInHTLC, claimAssetInHTLCusingContractId, claimFungibleAssetInHTLC, + assignAsset, reclaimAssetInHTLC, reclaimAssetInHTLCusingContractId, reclaimFungibleAssetInHTLC, diff --git a/weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts b/weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts new file mode 100644 index 0000000000..313c995765 --- /dev/null +++ b/weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts @@ -0,0 +1,1111 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * This file provides helper functions for interoperability operations. + **/ +/** End file docs */ + +import log4js from "log4js"; +import crypto from "crypto"; +import fabproto6 from "fabric-protos"; +import * as helpers from "./helpers"; +import assetLocksPb from "@hyperledger/cacti-weaver-protos-js/common/asset_locks_pb"; +import { Contract, ContractListener } from "fabric-network"; +import { Hash, SHA256, SHA512 } from "./HashFunctions" +const logger = log4js.getLogger("InteroperableHelper"); + + +// Create an asset exchange agreement structure +function createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, lockerECert) +{ + const assetExchangeAgreement = new assetLocksPb.AssetExchangeAgreement(); + assetExchangeAgreement.setAssettype(assetType); + assetExchangeAgreement.setId(assetID); + assetExchangeAgreement.setRecipient(recipientECert); + assetExchangeAgreement.setLocker(lockerECert); + return Buffer.from(assetExchangeAgreement.serializeBinary()).toString('base64'); +} + +// Create a fungible asset exchange agreement structure +function createFungibleAssetExchangeAgreementSerialized(assetType, numUnits, recipientECert, lockerECert) +{ + const assetExchangeAgreement = new assetLocksPb.FungibleAssetExchangeAgreement(); + assetExchangeAgreement.setAssettype(assetType); + assetExchangeAgreement.setNumunits(numUnits); + assetExchangeAgreement.setRecipient(recipientECert); + assetExchangeAgreement.setLocker(lockerECert); + return Buffer.from(assetExchangeAgreement.serializeBinary()).toString('base64'); +} + +// Create an asset lock structure +function createAssetLockInfoSerialized(hash, expiryTimeSecs) +{ + const lockInfoHTLC = new assetLocksPb.AssetLockHTLC(); + lockInfoHTLC.setHashmechanism(hash.HASH_MECHANISM); + lockInfoHTLC.setHashbase64(Buffer.from(hash.getSerializedHashBase64())); + lockInfoHTLC.setExpirytimesecs(expiryTimeSecs); + lockInfoHTLC.setTimespec(assetLocksPb.TimeSpec.EPOCH); + const lockInfoHTLCSerialized = lockInfoHTLC.serializeBinary(); + const lockInfo = new assetLocksPb.AssetLock(); + lockInfo.setLockmechanism(assetLocksPb.LockMechanism.HTLC); + lockInfo.setLockinfo(lockInfoHTLCSerialized); + return Buffer.from(lockInfo.serializeBinary()).toString('base64'); +} + +// Create an asset claim structure +function createAssetClaimInfoSerialized(hash) +{ + const claimInfoHTLC = new assetLocksPb.AssetClaimHTLC(); + claimInfoHTLC.setHashmechanism(hash.HASH_MECHANISM); + claimInfoHTLC.setHashpreimagebase64(Buffer.from(hash.getSerializedPreimageBase64())); + const claimInfoHTLCSerialized = claimInfoHTLC.serializeBinary(); + const claimInfo = new assetLocksPb.AssetClaim(); + claimInfo.setLockmechanism(assetLocksPb.LockMechanism.HTLC); + claimInfo.setClaiminfo(claimInfoHTLCSerialized); + return Buffer.from(claimInfo.serializeBinary()).toString('base64'); +} + +/** + * First/second step of a Hashed Time Lock Contract + * - Lock a unique asset instance using a hash + * + * Byzantine Swaps: Call StartHTLCAssetLockListener within here while passing new callback + * parameter as newly defined function: assetLockExpirationCallback is passed as localCallback + **/ +const createHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + recipientECert: string, + hash: Hash, + expiryTimeSecs: number, + timeoutCallback: (c: Contract, t: string, i: string, r: string, h: Hash) => any, + endorsingOrgs: Array = [], +): Promise<{ hash: Hash; result: any }> => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return { hash: null, result: false }; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return { hash: null, result: false }; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return { hash: null, result: false }; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return { hash: null, result: false }; + } + const currTimeSecs = Math.floor(Date.now()/1000); // Convert epoch milliseconds to seconds + if (expiryTimeSecs <= currTimeSecs) + { + logger.error("Supplied expiry time invalid or in the past: %s; current time: %s", new Date(expiryTimeSecs).toISOString(), new Date(currTimeSecs).toISOString()); + return { hash: null, result: false }; + } + + if (hash == null) { + hash = new SHA256() + } + if (hash.hash64 == null) { + hash.generateRandomPreimage(22); + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, ""); + const lockInfoStr = createAssetLockInfoSerialized(hash, expiryTimeSecs); + + //If timeoutCallback is not defined, start automated listener + if (!timeoutCallback) + { + StartHTLCAssetLockListener(contract, "", assetType, assetID, recipientECert, "", assetLockExpirationCallback, endorsingOrgs); + } + + const tx = contract.createTransaction("LockAsset") + const ccArgs = [assetExchangeAgreementStr, lockInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + // Normal invoke function + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`LockAsset submitTransaction Error: ${submitError}`); + } + + if (timeoutCallback) + { + // Start timer for lock expiration + setTimeout(timeoutCallback, (expiryTimeSecs * 1000) - Date.now(), contract, assetType, assetID, recipientECert, hash); + } + + return { hash: hash, result: result }; +}; + +/** + * First/second step of a Hashed Time Lock Contract + * - Lock a set of fungible assets using a hash + **/ +const createFungibleHTLC = async ( + contract: Contract, + assetType: string, + numUnits: number, + recipientECert: string, + hash: Hash, + expiryTimeSecs: number, + timeoutCallback: (c: Contract, i: string, t: string, n: number, r: string, h: Hash) => any, + endorsingOrgs: Array = [], +): Promise<{ hash: Hash; result: any }> => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return { hash: null, result: "" }; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return { hash: null, result: "" }; + } + if (numUnits <= 0) + { + logger.error("Asset count must be a positive integer"); + return { hash: null, result: "" }; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return { hash: null, result: "" }; + } + const currTimeSecs = Math.floor(Date.now()/1000); // Convert epoch milliseconds to seconds + if (expiryTimeSecs <= currTimeSecs) + { + logger.error("Supplied expiry time invalid or in the past: %s; current time: %s", new Date(expiryTimeSecs).toISOString(), new Date(currTimeSecs).toISOString()); + return { hash: null, result: "" }; + } + + if (!hash) { + hash = new SHA256() + } + if (hash.hash64 == null) { + hash.generateRandomPreimage(22); + } + + const assetExchangeAgreementStr = createFungibleAssetExchangeAgreementSerialized(assetType, numUnits, recipientECert, ""); + const lockInfoStr = createAssetLockInfoSerialized(hash, expiryTimeSecs); + + //If timeoutCallback is not defined, start automated listener + if (!timeoutCallback) + { + StartHTLCFungibleAssetLockListener(contract, "", assetType, numUnits, recipientECert, "", fungibleAssetLockExpirationCallback, endorsingOrgs); + } + + const tx = contract.createTransaction("LockFungibleAsset") + const ccArgs = [assetExchangeAgreementStr, lockInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + // Normal invoke function + const [contractId, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`LockFungibleAsset submitTransaction Error: ${submitError}`); + } + + if (timeoutCallback) + { + // Start timer for lock expiration + setTimeout(timeoutCallback, (expiryTimeSecs * 1000) - Date.now(), contract, contractId, assetType, numUnits, recipientECert, hash); + } + + return { hash: hash, result: contractId }; +}; + +/** + * Latter step of a Hashed Time Lock Contract + * - Claim a unique asset instance using a hash preimage + **/ +const claimAssetInHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + lockerECert: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, "", lockerECert); + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("ClaimAsset") + const ccArgs = [assetExchangeAgreementStr, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`ClaimAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +const assignAsset = async ( + contract: Contract, + assetType: string, + assetID: string, + lockerECert: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, "", lockerECert); + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("AssignAsset") + const ccArgs = [assetExchangeAgreementStr, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`AssignAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Latter step of a Hashed Time Lock Contract + * - Claim a unique asset instance using a hash preimage and contractId + **/ +const claimAssetInHTLCusingContractId = async ( + contract: Contract, + contractId: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("ClaimAssetUsingContractId") + const ccArgs = [contractId, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`ClaimAssetUsingContractId submitTransaction Error: ${submitError}`); + } + return result; +}; + + +/** + * Latter step of a Hashed Time Lock Contract + * - Claim a set of fungible assets using a hash preimage + **/ +const claimFungibleAssetInHTLC = async ( + contract: Contract, + contractId: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("ClaimFungibleAsset") + const ccArgs = [contractId, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`ClaimFungibleAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Rollback step of a Hashed Time Lock Contract + * - Reclaim a unique asset instance + **/ +const reclaimAssetInHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + recipientECert: string, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, ""); + + // Normal invoke function + const tx = contract.createTransaction("UnlockAsset") + const ccArgs = [assetExchangeAgreementStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`UnlockAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Rollback step of a Hashed Time Lock Contract + * - Reclaim a unique asset instance using contractId + **/ +const reclaimAssetInHTLCusingContractId = async ( + contract: Contract, + contractId: string, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const tx = contract.createTransaction("UnlockAssetUsingContractId") + const ccArgs = [contractId] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`UnlockAssetUsingContractId submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Rollback step of a Hashed Time Lock Contract + * - Reclaim a set of fungible assets + **/ +const reclaimFungibleAssetInHTLC = async ( + contract: Contract, + contractId: string, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const tx = contract.createTransaction("UnlockFungibleAsset") + const ccArgs = [contractId] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`UnlockFungibleAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Query the state of a Hashed Time Lock Contract + * - Determine if a unique asset instance is locked by a given party for another given party + **/ +const isAssetLockedInHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + recipientECert: string, + lockerECert: string, +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, lockerECert); + + // Normal invoke function + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("IsAssetLocked", assetExchangeAgreementStr), + ); + if (evaluateError) { + throw new Error(`IsAssetLocked evaluateTransaction Error: ${evaluateError}`); + } + return result.toString() === "true"; +}; + +/** + * Query the state of a Hashed Time Lock Contract using contractId + * - Determine if a unique asset instance is locked by a given party for another given party + **/ +const isAssetLockedInHTLCqueryUsingContractId = async ( + contract: Contract, + contractId: string, +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("IsAssetLockedQueryUsingContractId", contractId), + ); + if (evaluateError) { + throw new Error(`IsAssetLockedQueryUsingContractId evaluateTransaction Error: ${evaluateError}`); + } + return result.toString() === "true"; +}; + +/** + * Query the state of a Hashed Time Lock Contract + * - Determine if a set of fungible assets is locked by a given party for another given party + **/ +const isFungibleAssetLockedInHTLC = async ( + contract: Contract, + contractId: string, +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("IsFungibleAssetLocked", contractId), + ); + if (evaluateError) { + throw new Error(`IsFungibleAssetLocked evaluateTransaction Error: ${evaluateError}`); + } + return result.toString() === "true"; +}; + + +/** + * HTLC Lifecycle Events + * - Developers should note that event emission and actions in response occur on a best effort basis. + * - Also, there is no guarantee that a particular event (lock, claim, reclaim) will ever get emitted + * - Therefore, the calling (or listening) logic should incorporate suitable fallbacks and timeouts. + **/ + +/** + * The below functions trigger callbacks passed as arguments when a matching event is received from the contract layer + **/ +const StartHTLCEventListener = ( + contract: Contract, + eventName: string, + contractId: string, + assetType: string, + assetId: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + eventCallback: Function, + endorsingOrgs: Array = [], +): void => { + const listener: ContractListener = async (event) => { + if (event.eventName === eventName) { + let assetLockContractInfo; + + if (eventName.includes('Fungible')) { + const eventInfo: assetLocksPb.FungibleAssetContractHTLC = assetLocksPb.FungibleAssetContractHTLC.deserializeBinary(event.payload); + assetLockContractInfo = eventInfo; + } + else { + const eventInfo: assetLocksPb.AssetContractHTLC = assetLocksPb.AssetContractHTLC.deserializeBinary(event.payload); + assetLockContractInfo = eventInfo; + } + const infoContractId = assetLockContractInfo.getContractid(); + if (contractId && contractId.length > 0) { + if (infoContractId.length > 0 && infoContractId !== contractId) { + return; + } + } + const infoAssetType = assetLockContractInfo.getAgreement().getAssettype(); + if (assetType && assetType.length > 0) { + if (infoAssetType.length > 0 && infoAssetType !== assetType) { + return; + } + } + let infoNumUnits: number, infoAssetId: string; + if (eventName.includes('Fungible')) { + infoNumUnits = assetLockContractInfo.getAgreement().getNumunits(); + if (infoNumUnits != numUnits) { + return; + } + } + else { + infoAssetId = assetLockContractInfo.getAgreement().getId(); + if (assetId && assetId.length > 0) { + if (infoAssetId.length > 0 && infoAssetId !== assetId) { + return; + } + } + } + const infoRecipient = assetLockContractInfo.getAgreement().getRecipient(); + if (recipientECert && recipientECert.length > 0) { + if (infoRecipient.length > 0 && infoRecipient !== recipientECert) { + return; + } + } + const infoLocker = assetLockContractInfo.getAgreement().getLocker(); + if (lockerECert && lockerECert.length > 0) { + if (infoLocker.length > 0 && infoLocker !== lockerECert) { + return; + } + } + // All filters passed + if (eventName === 'LockAsset' || eventName === 'LockFungibleAsset') { + const timeout = assetLockContractInfo.getLock().getExpirytimesecs(); + const hashBase64 = assetLockContractInfo.getLock().getHashbase64(); + let hash: Hash; + + const hashMechanism = assetLockContractInfo.getLock().getHashmechanism(); + if (hashMechanism === assetLocksPb.HashMechanism.SHA256) { + hash = new SHA256(); + } + else if (hashMechanism === assetLocksPb.HashMechanism.SHA512) { + hash = new SHA512(); + } + else { + throw new Error(`Hash Mechanism not supported`); + } + hash.setSerializedHashBase64(hashBase64); + // We only care about timeouts for locking the asset, not for the unlock itself + if (eventName === 'LockAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoAssetId, infoRecipient, infoLocker, hash, timeout, endorsingOrgs); + } + else { + eventCallback(contract, infoContractId, infoAssetType, infoNumUnits, infoRecipient, infoLocker, hash, timeout, endorsingOrgs); + } + } else if (eventName === 'ClaimAsset' || eventName === 'ClaimFungibleAsset') { + const hashPreimageBase64 = assetLockContractInfo.getClaim().getHashpreimagebase64(); + const hashPreimage: string = Buffer.from(hashPreimageBase64.toString(), 'base64').toString('utf8'); + if (eventName === 'ClaimAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoAssetId, infoRecipient, infoLocker, hashPreimage); + } + else { + eventCallback(contract, infoContractId, infoAssetType, infoNumUnits, infoRecipient, infoLocker, hashPreimage); + } + } + else if (eventName === 'UnlockAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoAssetId, infoRecipient, infoLocker); + } + else if (eventName === 'UnlockFungibleAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoNumUnits, infoRecipient, infoLocker); + } + } + }; + contract.addContractListener(listener); +} + +const StartHTLCAssetLockListener = ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, + lockCallback: (c: Contract, d: string, t: string, i: string, r: string, l: string, v: Hash, timeout: number, eOrgs: Array) => any, + endorsingOrgs: Array = [], +): void => { + StartHTLCEventListener(contract, 'LockAsset', contractId, assetType, assetId, -1, recipientECert, lockerECert, lockCallback, endorsingOrgs); +} + +// NOTE: For Nonfungible Assets +// Byzantine Swaps: Timed counterpart for timed AssetLockListener for reversion +const assetLockExpirationCallback = ( + contract: Contract, + contractID: string, + assetType: string, + assetID: string, + recipientECert: string, + lockerECert: string, + hash: Hash, + expiryTime: number, + endorsingOrgs: Array = [] +): void => { + // Compare expiryTimeSec with currentTimeSec, which is number of milliseconds since epoch (L174) + const currTimeSecs = Math.floor(Date.now()/1000); + const reclaimCallback = async (contract: Contract, contractID: string) => { + // Check if asset hasn't been claimed yet. If true, do nothing. If false, either do the following cases: + const [islocked, isLockedQueryError] = await helpers.handlePromise(isAssetLockedInHTLCqueryUsingContractId(contract, contractID)); + if (islocked === false) { + // CASE #1: Check GetHTLCHashPreImageByContractId(contractId) + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("GetHTLCHashPreImageByContractId", contractID), + ); + + // CASE #2: If the function above returns ANY error, call reclaimAssetInHTLC + if (evaluateError) { + // Put retry logic in event of failure. Retry 3x and then give up if unsuccessful (temp solution for now; requires CORE changes) + // If it fails, retry for i (arbitrarily defined) more attempts until you quit + let i = 0; + do { + let [retryReclaimResult, retryReclaimableQueryError] = await helpers.handlePromise(reclaimAssetInHTLCusingContractId(contract, contractID, endorsingOrgs)); + if (!retryReclaimableQueryError) { + console.log("Nonfungible Asset unlocked successfully"); + break; + } + + i++; + } while (i < 3); + } + } + } + + // If you have time remaining, call setTimeout with reclaimCallback + if (expiryTime - currTimeSecs > 0) { + setTimeout(reclaimCallback, 1000 * (expiryTime - currTimeSecs), contract, contractID); + } else { + // If no time remaining, call the reclaim callback immediately + reclaimCallback(contract, contractID); + } +} + +//NOTE: FUNGIBLE counterpart +// Byzantine Swaps: Timed counterpart for timed AssetLockListener for reversion +const fungibleAssetLockExpirationCallback = ( + contract: Contract, + contractID: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + hash: Hash, + expiryTime: number, + endorsingOrgs: Array = [] +): void => { + // Compare expiryTimeSec with currentTimeSec, which is number of milliseconds since epoch (L174) + const currTimeSecs = Math.floor(Date.now()/1000); + const reclaimCallback = async (contract: Contract, contractID: string) => { + // Check if asset hasn't been claimed yet. If true, do nothing. If false, either do the following cases: + const [islocked, isLockedQueryError] = await helpers.handlePromise(isFungibleAssetLockedInHTLC(contract, contractID)); + + if (islocked === false) { + // CASE #1: Check GetHTLCHashPreImageByContractId(contractId) + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("GetHTLCHashPreImageByContractId", contractID), + ); + + // CASE #2: If the function above returns ANY error, call reclaimAssetInHTLC + if (evaluateError) { + // Put retry logic in event of failure. Retry 3x and then give up if unsuccessful (temp solution for now; requires CORE changes) + // If it fails, retry for i (arbitrarily defined) more attempts until you quit + let i = 0; + do { + let [retryReclaimResult, retryReclaimableQueryError] = await helpers.handlePromise(reclaimFungibleAssetInHTLC(contract, contractID, endorsingOrgs)); + if (!retryReclaimableQueryError) { + console.log("Fungible Asset unlocked successfully"); + break; + } + + i++; + } while (i < 3); + } + } + } + + // If you have time remaining, call setTimeout with reclaimCallback + if (expiryTime - currTimeSecs > 0) { + setTimeout(reclaimCallback, 1000 * (expiryTime - currTimeSecs), contract, contractID); + } else { + // If no time remaining, call the reclaim callback immediately + reclaimCallback(contract, contractID); + } +} + +const StartHTLCAssetClaimListener = ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, + claimCallback: (c: Contract, d: string, t: string, i: string, r: string, l: string, p: string) => any, +): void => { + StartHTLCEventListener(contract, 'ClaimAsset', contractId, assetType, assetId, -1, recipientECert, lockerECert, claimCallback); +} + +const StartHTLCAssetUnlockListener = ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, + unlockCallback: (c: Contract, d: string, t: string, i: string, r: string, l: string) => any, +): void => { + StartHTLCEventListener(contract, 'UnlockAsset', contractId, assetType, assetId, -1, recipientECert, lockerECert, unlockCallback); +} + +const StartHTLCFungibleAssetLockListener = ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + lockCallback: (c: Contract, d: string, t: string, n: number, r: string, l: string, v: Hash, timeout: number, eOrgs: Array) => any, + endorsingOrgs: Array = [], +): void => { + StartHTLCEventListener(contract, 'LockFungibleAsset', contractId, assetType, "", numUnits, recipientECert, lockerECert, lockCallback, endorsingOrgs); +} + +const StartHTLCFungibleAssetClaimListener = ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + claimCallback: (c: Contract, d: string, t: string, n: number, r: string, l: string, p: string) => any, +): void => { + StartHTLCEventListener(contract, 'ClaimFungibleAsset', contractId, assetType, "", numUnits, recipientECert, lockerECert, claimCallback); +} + +const StartHTLCFungibleAssetUnlockListener = ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + unlockCallback: (c: Contract, d: string, t: string, n: number, r: string, l: string) => any, +): void => { + StartHTLCEventListener(contract, 'UnlockFungibleAsset', contractId, assetType, "", numUnits, recipientECert, lockerECert, unlockCallback); +} + +/** + * The below functions return promises for HTLC events. + * Developers can use 'await' to synchronously manage asset swapping logic. + **/ + const HTLCAssetLocked = async ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForLock = (contract, contractId, assetType, assetId, recipientECert, lockerECert, hashValue) => { + resolve(hashValue); + }; + StartHTLCAssetLockListener(contract, contractId, assetType, assetId, recipientECert, lockerECert, waitForLock); + }); +} + +const HTLCAssetClaimed = async ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForClaim = (contract, contractId, assetType, assetId, recipientECert, lockerECert, hashPreimage) => { + resolve(hashPreimage); + }; + StartHTLCAssetClaimListener(contract, contractId, assetType, assetId, recipientECert, lockerECert, waitForClaim); + }); +} + +const HTLCAssetUnlocked = async ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForUnlock = (contract, contractId, assetType, assetId, recipientECert, lockerECert) => { + resolve(); + }; + StartHTLCAssetUnlockListener(contract, contractId, assetType, assetId, recipientECert, lockerECert, waitForUnlock); + }); +} + +const HTLCFungibleAssetLocked = async ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForLock = (contract, contractId, assetType, numUnits, recipientECert, lockerECert, hashValue) => { + resolve(hashValue); + }; + StartHTLCFungibleAssetLockListener(contract, contractId, assetType, numUnits, recipientECert, lockerECert, waitForLock); + }); +} + +const HTLCFungibleAssetClaimed = async ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForClaim = (contract, contractId, assetType, numUnits, recipientECert, lockerECert, hashPreimage) => { + resolve(hashPreimage); + }; + StartHTLCFungibleAssetClaimListener(contract, contractId, assetType, numUnits, recipientECert, lockerECert, waitForClaim); + }); +} + +const HTLCFungibleAssetUnlocked = async ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForUnlock = (contract, contractId, assetType, numUnits, recipientECert, lockerECert) => { + resolve(); + }; + StartHTLCFungibleAssetUnlockListener(contract, contractId, assetType, numUnits, recipientECert, lockerECert, waitForUnlock); + }); +} + +export { + createAssetExchangeAgreementSerialized, + createFungibleAssetExchangeAgreementSerialized, + createAssetLockInfoSerialized, + createAssetClaimInfoSerialized, + createHTLC, + createFungibleHTLC, + claimAssetInHTLC, + claimAssetInHTLCusingContractId, + claimFungibleAssetInHTLC, + reclaimAssetInHTLC, + reclaimAssetInHTLCusingContractId, + reclaimFungibleAssetInHTLC, + assignAsset, + isAssetLockedInHTLC, + isAssetLockedInHTLCqueryUsingContractId, + isFungibleAssetLockedInHTLC, + StartHTLCAssetLockListener, + StartHTLCAssetClaimListener, + StartHTLCAssetUnlockListener, + StartHTLCFungibleAssetLockListener, + StartHTLCFungibleAssetClaimListener, + StartHTLCFungibleAssetUnlockListener, + HTLCAssetLocked, + HTLCAssetClaimed, + HTLCAssetUnlocked, + HTLCFungibleAssetLocked, + HTLCFungibleAssetClaimed, + HTLCFungibleAssetUnlocked, +}; diff --git a/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts b/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts index 4ec78c0f11..f965212e3e 100644 --- a/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts +++ b/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts @@ -14,6 +14,8 @@ import * as RelayHelper from "../src/Relay"; export { RelayHelper }; import * as AssetManager from "../src/AssetManager"; export { AssetManager }; +import * as SatpAssetManager from "../src/SatpAssetManager"; +export { SatpAssetManager }; import * as HashFunctions from "../src/HashFunctions"; export { HashFunctions }; import * as EventsManager from "../src/EventsManager"; diff --git a/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh b/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh index 9e6ff728e1..571da3477e 100755 --- a/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh +++ b/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh @@ -298,6 +298,10 @@ chaincodeInvokeInit() { peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Bond", "interop"]}' >&log.txt elif [ "$CC_CHAIN_CODE" = "simpleasset" ] && [ "$NW_NAME" = "network2" ]; then peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Token", "interop"]}' >&log.txt + elif [ "$CC_CHAIN_CODE" = "satpsimpleasset" ] && [ "$NW_NAME" = "network1" ]; then + peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Bond", "interop"]}' >&log.txt + elif [ "$CC_CHAIN_CODE" = "satpsimpleasset" ] && [ "$NW_NAME" = "network2" ]; then + peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Token", "interop"]}' >&log.txt elif [ "$CC_CHAIN_CODE" = "simpleassettransfer" ] && [ "$NW_NAME" = "network1" ]; then peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["interop", "network1"]}' >&log.txt elif [ "$CC_CHAIN_CODE" = "simpleassettransfer" ] && [ "$NW_NAME" = "network2" ]; then From 9543ac69ffbf1b14941364d226b95ddf5d77c128 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 12 Sep 2023 08:23:19 +0100 Subject: [PATCH 26/59] uncommented the perform lock part --- .../core/drivers/fabric-driver/server/satp.ts | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index 0f0eef77b5..a1c6c6ca1c 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -104,17 +104,17 @@ async function performLockHelper( console.info(`Asset Lock: Lock ${asset}:\n`); try { console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) - // const res = await funcToCall(network.contract, - // params[0], - // params[1], - // recipientCert, - // hash, - // timeout, - // null) - // if (!res.result) { - // throw new Error() - // } - // console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) + const res = await funcToCall(network.contract, + params[0], + params[1], + recipientCert, + hash, + timeout, + null) + if (!res.result) { + throw new Error() + } + console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) console.info('Asset has been locked successfully') } catch (error) { @@ -144,7 +144,7 @@ async function createAssetHelper( createAssetRequest2['owner'] = 'admin'; createAssetRequest2['type'] = 'bond'; createAssetRequest2['assetType'] = 'bond01'; - createAssetRequest2['id'] = 'a065'; + createAssetRequest2['id'] = 'a0demo'; createAssetRequest2['issuer'] = 'admin'; createAssetRequest2['facevalue'] = '300'; createAssetRequest2['maturitydate'] = '05 May 48 00:00 MST'; @@ -254,7 +254,7 @@ async function assignAssetHelper( assignAssetRequest2['contract-id'] = 'abc01'; assignAssetRequest2['hash_fn'] = ''; assignAssetRequest2['secret'] = 'secrettext'; - assignAssetRequest2['param'] = 'bond01:a065'; + assignAssetRequest2['param'] = 'bond01:a0demo'; const targetNetwork = assignAssetRequest2['target-network']; const locker = assignAssetRequest2['locker']; From 4d5f6c2052324eaeea71d19526af56d6592c801e Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Wed, 2 Aug 2023 10:04:33 +0100 Subject: [PATCH 27/59] implemented the lock assertion method --- weaver/core/relay/src/services/satp_helper.rs | 86 +++++++++++++- .../core/relay/src/services/satp_service.rs | 111 ++++++++++++++++-- 2 files changed, 183 insertions(+), 14 deletions(-) diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 9405543f35..95e352fe45 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -10,7 +10,7 @@ use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ AckCommenceRequest, LockAssertionRequest, TransferCommenceRequest, - TransferProposalClaimsRequest, TransferProposalReceiptRequest, + TransferProposalClaimsRequest, TransferProposalReceiptRequest, LockAssertionReceiptRequest, }; use crate::db::Database; @@ -187,6 +187,35 @@ pub fn spawn_send_perform_lock_request( }); } +pub fn spawn_send_lock_assertion_receipt_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + relay_tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = lock_assertion_receipt_request.session_id.to_string(); + println!( + "Sending lock assertion receipt back to sending gateway: Request ID = {:?}", + request_id + ); + let result = call_lock_assertion_receipt( + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path.to_string(), + lock_assertion_receipt_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + // Call the transfer_commence endpoint on the receiver gateway pub async fn call_transfer_commence( relay_host: String, @@ -287,6 +316,26 @@ pub async fn call_lock_assertion( Ok(response) } +// Call the ack_commence endpoint on the sending gateway +pub async fn call_lock_assertion_receipt( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the lock assertion receipt request: {:?}", + lock_assertion_receipt_request.clone() + ); + let response = satp_client + .lock_assertion_receipt(lock_assertion_receipt_request.clone()) + .await?; + Ok(response) +} + pub fn log_request_result_in_local_satp_db( request_id: &String, result: Result, Box>, @@ -446,6 +495,23 @@ pub fn create_lock_assertion_request( return lock_assertion_request; } +pub fn create_lock_assertion_receipt_request( + lock_assertion_request: LockAssertionRequest, +) -> LockAssertionReceiptRequest { + // TODO: remove hard coded values + let lock_assertion_receipt_request = LockAssertionReceiptRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + hash_prev_message: "hash_prev_message1".to_string(), + server_transfer_number: "server_transfer_number1".to_string(), + server_signature: "server_signature1".to_string(), + }; + return lock_assertion_receipt_request; +} + pub fn get_satp_requests_local_db(conf: Config) -> Database { let db = Database { db_path: format!( @@ -554,7 +620,6 @@ pub fn update_request_state_in_local_satp_db( println!("{:?}\n", db.get::(request_id).unwrap()) } -// Get the requesting relay host and port pub fn get_relay_from_transfer_proposal_claims( transfer_proposal_claims_request: TransferProposalClaimsRequest, ) -> (String, String) { @@ -562,7 +627,6 @@ pub fn get_relay_from_transfer_proposal_claims( return ("localhost".to_string(), "9085".to_string()); } -// Get the requesting relay host and port pub fn get_relay_from_transfer_proposal_receipt( transfer_proposal_receipt_request: TransferProposalReceiptRequest, ) -> (String, String) { @@ -570,7 +634,6 @@ pub fn get_relay_from_transfer_proposal_receipt( return ("localhost".to_string(), "9085".to_string()); } -// Get the requesting relay host and port pub fn get_relay_from_transfer_commence( transfer_commence_request: TransferCommenceRequest, ) -> (String, String) { @@ -578,12 +641,25 @@ pub fn get_relay_from_transfer_commence( return ("localhost".to_string(), "9085".to_string()); } -// Get the requesting relay host and port pub fn get_relay_from_ack_commence(ack_commence_request: AckCommenceRequest) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } +pub fn get_relay_from_lock_assertion( + lock_assertion_request: LockAssertionRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_lock_assertion_receipt( + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 8037f6127e..35e778b0d8 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -21,7 +21,7 @@ use super::satp_helper::{ get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, spawn_send_perform_lock_request, spawn_send_transfer_commence_request, - spawn_send_transfer_proposal_receipt_request, + spawn_send_transfer_proposal_receipt_request, get_relay_from_lock_assertion, create_lock_assertion_receipt_request, get_relay_from_lock_assertion_receipt, spawn_send_lock_assertion_receipt_request, }; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; @@ -247,17 +247,44 @@ impl Satp for SatpService { request: Request, ) -> Result, Status> { println!( - "Got a lock assertion request from {:?} - {:?}", + "Got a LockAssertionRequest from {:?} - {:?}", request.remote_addr(), request ); - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: "xxxxxxxxx".to_string(), - message: format!("Error: Not implemented yet."), - })); - println!("Sending back Ack: {:?}\n", reply); - reply + + let lock_assertion_request = request.into_inner().clone(); + let request_id = lock_assertion_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + match log_request_in_remote_satp_db(&request_id, &lock_assertion_request, conf.clone()) { + Ok(_) => { + println!("Successfully stored LockAssertionRequest in remote satp_db with request_id: {}", request_id); + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing LockAssertionRequest in remote satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_lock_assertion_request(lock_assertion_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of lock assertion request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Lock assertion failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } } async fn lock_assertion_receipt( @@ -461,6 +488,40 @@ pub fn process_ack_commence_request( } } +pub fn process_lock_assertion_request( + lock_assertion_request: LockAssertionRequest, + conf: config::Config, +) -> Result { + let request_id = lock_assertion_request.session_id.to_string(); + let is_valid_request = is_valid_lock_assertion_request(lock_assertion_request.clone()); + + if is_valid_request { + println!("The lock assertion request is valid\n"); + match send_lock_assertion_receipt_request(lock_assertion_request, conf) { + Ok(ack) => { + println!("Ack lock assertion request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: Ack lock assertion failed. {:?}", e), + }); + } + } + } else { + println!("The lock assertion request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The lock assertion request is invalid".to_string(), + }); + } +} + fn send_transfer_proposal_receipt_request( transfer_proposal_claims_request: TransferProposalClaimsRequest, conf: config::Config, @@ -546,6 +607,33 @@ fn send_ack_commence_request( return Ok(reply); } +fn send_lock_assertion_receipt_request( + lock_assertion_request: LockAssertionRequest, + conf: config::Config, +) -> Result { + let request_id = &lock_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_lock_assertion(lock_assertion_request.clone()); + let (use_tls, relay_tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let lock_assertion_receipt_request = create_lock_assertion_receipt_request(lock_assertion_request.clone()); + + spawn_send_lock_assertion_receipt_request( + lock_assertion_receipt_request, + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Lock Assertion request".to_string(), + }; + return Ok(reply); +} + fn send_perform_lock_request( ack_commence_request: AckCommenceRequest, conf: config::Config, @@ -595,3 +683,8 @@ fn is_valid_ack_commence_request(ack_commence_request: AckCommenceRequest) -> bo //TODO true } + +fn is_valid_lock_assertion_request(lock_assertion_request: LockAssertionRequest) -> bool { + //TODO + true +} \ No newline at end of file From d25842cf656e7bdd772a76e77d19fdf3e42a05fa Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Wed, 2 Aug 2023 11:50:38 +0100 Subject: [PATCH 28/59] Added the lock-assertion-receipt and lock-assertion-broadcast methods --- weaver/core/relay/src/services/satp_helper.rs | 22 ++- .../core/relay/src/services/satp_service.rs | 164 +++++++++++++++--- 2 files changed, 155 insertions(+), 31 deletions(-) diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 95e352fe45..88f97cacf9 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -9,8 +9,8 @@ use weaverpb::common::state::{request_state, RequestState}; use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ - AckCommenceRequest, LockAssertionRequest, TransferCommenceRequest, - TransferProposalClaimsRequest, TransferProposalReceiptRequest, LockAssertionReceiptRequest, + AckCommenceRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, + TransferProposalClaimsRequest, TransferProposalReceiptRequest, }; use crate::db::Database; @@ -162,9 +162,10 @@ pub fn spawn_send_perform_lock_request( conf: Config, ) { tokio::spawn(async move { + let request_id = lock_assertion_request.session_id.to_string(); println!( - "Locking the asset of the lock assertion request {:?}", - lock_assertion_request + "Locking the asset of the lock assertion request id: {:?}", + request_id ); // TODO // Call the driver to check the asset status @@ -187,7 +188,7 @@ pub fn spawn_send_perform_lock_request( }); } -pub fn spawn_send_lock_assertion_receipt_request( +pub fn spawn_send_lock_assertion_broadcast_request( lock_assertion_receipt_request: LockAssertionReceiptRequest, relay_host: String, relay_port: String, @@ -197,10 +198,12 @@ pub fn spawn_send_lock_assertion_receipt_request( ) { tokio::spawn(async move { let request_id = lock_assertion_receipt_request.session_id.to_string(); - println!( - "Sending lock assertion receipt back to sending gateway: Request ID = {:?}", - request_id - ); + println!("Broadcasting the lock assertion request {:?}", request_id); + // TODO + // Broadcast the message to the network + // Subscribe to the status event + // Once the message is broadcast, call the call_lock_assertion_receipt endpoint + // log the results let result = call_lock_assertion_receipt( relay_host, relay_port, @@ -212,6 +215,7 @@ pub fn spawn_send_lock_assertion_receipt_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway + let request_id = lock_assertion_receipt_request.session_id.to_string(); log_request_result_in_local_satp_db(&request_id, result, conf); }); } diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 35e778b0d8..71fe74b7d0 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -15,13 +15,15 @@ use crate::services::satp_helper::{ // external modules use super::satp_helper::{ - create_ack_commence_request, create_lock_assertion_request, create_transfer_commence_request, + create_ack_commence_request, create_lock_assertion_receipt_request, + create_lock_assertion_request, create_transfer_commence_request, create_transfer_proposal_receipt_request, get_relay_from_ack_commence, - get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, - get_relay_from_transfer_proposal_receipt, get_relay_params, - get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, + get_relay_from_lock_assertion, get_relay_from_transfer_commence, + get_relay_from_transfer_proposal_claims, get_relay_from_transfer_proposal_receipt, + get_relay_params, get_request_id_from_transfer_proposal_claims, + spawn_send_ack_commence_request, spawn_send_lock_assertion_broadcast_request, spawn_send_perform_lock_request, spawn_send_transfer_commence_request, - spawn_send_transfer_proposal_receipt_request, get_relay_from_lock_assertion, create_lock_assertion_receipt_request, get_relay_from_lock_assertion_receipt, spawn_send_lock_assertion_receipt_request, + spawn_send_transfer_proposal_receipt_request, }; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; @@ -273,10 +275,7 @@ impl Satp for SatpService { match process_lock_assertion_request(lock_assertion_request, conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); - println!( - "Sending Ack of lock assertion request back: {:?}\n", - reply - ); + println!("Sending Ack of lock assertion request back: {:?}\n", reply); reply } Err(e) => { @@ -292,17 +291,53 @@ impl Satp for SatpService { request: Request, ) -> Result, Status> { println!( - "Got a lock assertion receipt request from {:?} - {:?}", + "Got an lock assertion receipt request from {:?} - {:?}", request.remote_addr(), request ); - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: "xxxxxxxxx".to_string(), - message: format!("Error: Not implemented yet."), - })); - println!("Sending back Ack: {:?}\n", reply); - reply + + let lock_assertion_receipt_request = request.into_inner().clone(); + let request_id = lock_assertion_receipt_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = log_request_in_local_satp_db( + &request_id, + &lock_assertion_receipt_request, + conf.clone(), + ); + match request_logged { + Ok(_) => { + println!( + "Successfully stored LockAssertionReceiptRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing LockAssertionReceiptRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_lock_assertion_receipt_request(lock_assertion_receipt_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of lock assertion receipt request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Lock assertion receipt failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } } } @@ -522,6 +557,42 @@ pub fn process_lock_assertion_request( } } +pub fn process_lock_assertion_receipt_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, + conf: config::Config, +) -> Result { + let request_id = lock_assertion_receipt_request.session_id.to_string(); + let is_valid_request = + is_valid_lock_assertion_receipt_request(lock_assertion_receipt_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The lock assertion receipt request is valid\n"); + match send_commit_prepare_request(lock_assertion_receipt_request, conf) { + Ok(ack) => { + println!("Ack lock assertion receipt request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: perform lock request failed. {:?}", e), + }); + } + } + } else { + println!("The lock assertion receipt request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The lock assertion receipt request is invalid".to_string(), + }); + } +} + fn send_transfer_proposal_receipt_request( transfer_proposal_claims_request: TransferProposalClaimsRequest, conf: config::Config, @@ -612,13 +683,13 @@ fn send_lock_assertion_receipt_request( conf: config::Config, ) -> Result { let request_id = &lock_assertion_request.session_id.to_string(); - let (relay_host, relay_port) = - get_relay_from_lock_assertion(lock_assertion_request.clone()); + let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); let (use_tls, relay_tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let lock_assertion_receipt_request = create_lock_assertion_receipt_request(lock_assertion_request.clone()); + let lock_assertion_receipt_request = + create_lock_assertion_receipt_request(lock_assertion_request.clone()); - spawn_send_lock_assertion_receipt_request( + spawn_send_lock_assertion_broadcast_request( lock_assertion_receipt_request, relay_host, relay_port, @@ -652,6 +723,7 @@ fn send_perform_lock_request( relay_tlsca_cert_path, conf, ); + let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), @@ -660,6 +732,47 @@ fn send_perform_lock_request( return Ok(reply); } +fn send_lock_assertion_broadcast_request( + lock_assertion_request: LockAssertionRequest, + conf: config::Config, +) -> Result { + let request_id = &lock_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); + let (use_tls, relay_tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let lock_assertion_receipt_request = + create_lock_assertion_receipt_request(lock_assertion_request.clone()); + + spawn_send_lock_assertion_broadcast_request( + lock_assertion_receipt_request, + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of lock assert request".to_string(), + }; + return Ok(reply); +} + +fn send_commit_prepare_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &lock_assertion_receipt_request.session_id.to_string(); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Lock Assertion Receipt request".to_string(), + }; + return Ok(reply); +} + fn is_valid_transfer_proposal_claims_request( transfer_proposal_claims_request: TransferProposalClaimsRequest, ) -> bool { @@ -687,4 +800,11 @@ fn is_valid_ack_commence_request(ack_commence_request: AckCommenceRequest) -> bo fn is_valid_lock_assertion_request(lock_assertion_request: LockAssertionRequest) -> bool { //TODO true -} \ No newline at end of file +} + +fn is_valid_lock_assertion_receipt_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> bool { + //TODO + true +} From d10ef02b456ed2dd784e36b22395c46b6d22f2c5 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Thu, 3 Aug 2023 11:47:25 +0100 Subject: [PATCH 29/59] Added the request to the driver to lock an asset --- .../pkg/src/generated/driver.driver.rs | 77 +++++++++++++++++++ .../protos-rs/pkg/src/generated/relay.satp.rs | 8 +- weaver/common/protos/driver/driver.proto | 6 ++ weaver/core/relay/driver/driver.rs | 14 +++- weaver/core/relay/src/services/satp_helper.rs | 58 +++++++++++++- .../core/relay/src/services/satp_service.rs | 57 +++++++++----- 6 files changed, 192 insertions(+), 28 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs index b846c9e7d5..188e49d79c 100644 --- a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs +++ b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs @@ -12,6 +12,10 @@ pub struct WriteExternalStateMessage { #[prost(message, optional, tag = "2")] pub ctx: ::core::option::Option, } +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerformLockRequest {} /// Generated client implementations. pub mod driver_communication_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] @@ -183,6 +187,30 @@ pub mod driver_communication_client { ); self.inner.unary(request.into_request(), path, codec).await } + /// As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + /// to lock a specific asset + pub async fn perform_lock( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/PerformLock", + ); + self.inner.unary(request.into_request(), path, codec).await + } } } /// Generated server implementations. @@ -234,6 +262,15 @@ pub mod driver_communication_server { tonic::Response, tonic::Status, >; + /// As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + /// to lock a specific asset + async fn perform_lock( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct DriverCommunicationServer { @@ -469,6 +506,46 @@ pub mod driver_communication_server { }; Box::pin(fut) } + "/driver.driver.DriverCommunication/PerformLock" => { + #[allow(non_camel_case_types)] + struct PerformLockSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for PerformLockSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).perform_lock(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = PerformLockSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index 0031a5dacd..743a57a40b 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -221,7 +221,7 @@ pub mod satp_client { self.inner = self.inner.accept_compressed(encoding); self } - /// The sender gateway sends a TransferProposalClaims request to to initiate an asset transfer. + /// The sender gateway sends a TransferProposalClaims request to initiate an asset transfer. /// Depending on the proposal, multiple rounds of communication between the two gateways may happen. pub async fn transfer_proposal_claims( &mut self, @@ -319,7 +319,7 @@ pub mod satp_client { } /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway /// declaring that the asset in question has been locked or escrowed by the sender gateway in - /// the origin network (e.g. to prevent double spending + /// the origin network (e.g. to prevent double spending) pub async fn lock_assertion( &mut self, request: impl tonic::IntoRequest, @@ -375,7 +375,7 @@ pub mod satp_server { /// Generated trait containing gRPC methods that should be implemented for use with SatpServer. #[async_trait] pub trait Satp: Send + Sync + 'static { - /// The sender gateway sends a TransferProposalClaims request to to initiate an asset transfer. + /// The sender gateway sends a TransferProposalClaims request to initiate an asset transfer. /// Depending on the proposal, multiple rounds of communication between the two gateways may happen. async fn transfer_proposal_claims( &self, @@ -413,7 +413,7 @@ pub mod satp_server { >; /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway /// declaring that the asset in question has been locked or escrowed by the sender gateway in - /// the origin network (e.g. to prevent double spending + /// the origin network (e.g. to prevent double spending) async fn lock_assertion( &self, request: tonic::Request, diff --git a/weaver/common/protos/driver/driver.proto b/weaver/common/protos/driver/driver.proto index fd12529aff..a11cae23f2 100644 --- a/weaver/common/protos/driver/driver.proto +++ b/weaver/common/protos/driver/driver.proto @@ -20,6 +20,8 @@ message WriteExternalStateMessage { common.events.ContractTransaction ctx = 2; } +message PerformLockRequest {} + service DriverCommunication { // Data Sharing // the remote relay sends a RequestDriverState request to its driver with a @@ -38,4 +40,8 @@ service DriverCommunication { // Events Publication // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger rpc WriteExternalState(WriteExternalStateMessage) returns (common.ack.Ack) {} + + // As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + // to lock a specific asset + rpc PerformLock(PerformLockRequest) returns (common.ack.Ack) {} } \ No newline at end of file diff --git a/weaver/core/relay/driver/driver.rs b/weaver/core/relay/driver/driver.rs index 3c8f25d4a0..7e8721ccc7 100644 --- a/weaver/core/relay/driver/driver.rs +++ b/weaver/core/relay/driver/driver.rs @@ -10,7 +10,7 @@ use weaverpb::common::query::Query; use weaverpb::common::events::EventSubscription; use weaverpb::common::state::{view_payload, Meta, meta, ViewPayload, View}; use weaverpb::driver::driver::driver_communication_server::{DriverCommunication, DriverCommunicationServer}; -use weaverpb::driver::driver::WriteExternalStateMessage; +use weaverpb::driver::driver::{WriteExternalStateMessage, PerformLockRequest}; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; @@ -208,6 +208,18 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(reply_error)); } + + async fn perform_lock(&self, request: Request) -> Result, Status> { + println!("Got a request from {:?}", request.remote_addr()); + println!("The asset has been locked"); + let request_id = "to_do".to_string(); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id, + message: "".to_string(), + }; + return Ok(Response::new(reply)); + } } fn send_driver_mock_state_helper(client: DataTransferClient, request_id: String) { diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 88f97cacf9..8139d52f5e 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -6,6 +6,7 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use tonic::Response; use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::state::{request_state, RequestState}; +use weaverpb::driver::driver::PerformLockRequest; use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ @@ -16,11 +17,13 @@ use weaverpb::relay::satp::{ use crate::db::Database; use crate::error::{self, Error}; use crate::relay_proto::LocationSegment; +use crate::services::helpers::get_driver_client; use super::constants::{ SATP_DB_PATH, SATP_REMOTE_REQUESTS_DB_PATH, SATP_REMOTE_REQUESTS_STATES_DB_PATH, SATP_REQUESTS_DB_PATH, SATP_REQUESTS_STATES_DB_PATH, }; +use super::types::Driver; // Sends a request to the receiving gateway pub fn spawn_send_transfer_proposal_claims_request( @@ -154,6 +157,8 @@ pub fn spawn_send_ack_commence_request( } pub fn spawn_send_perform_lock_request( + driver_info: Driver, + ack_commence_request: AckCommenceRequest, lock_assertion_request: LockAssertionRequest, relay_host: String, relay_port: String, @@ -167,11 +172,21 @@ pub fn spawn_send_perform_lock_request( "Locking the asset of the lock assertion request id: {:?}", request_id ); - // TODO - // Call the driver to check the asset status - // Subscribe to the status event + // TODO: pass the required info to lock the relevant asset + // Call the driver to lock the asset + let result = call_perform_lock(driver_info, ack_commence_request).await; + match result { + Ok(_) => { + println!("Ack Ok from driver\n") + } + Err(e) => { + println!("Error sending query to driver: {:?}\n", e); + // TODO: what to do in this case? + } + } + + // TODO: Subscribe to the status event // Once the asset is locked, call the lock_assertion endpoint - // log the results let result = call_lock_assertion( relay_host, relay_port, @@ -220,6 +235,30 @@ pub fn spawn_send_lock_assertion_broadcast_request( }); } +async fn call_perform_lock( + driver_info: Driver, + ack_commence_request: AckCommenceRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to lock the asset"); + let perform_lock_request = create_perform_lock_request(ack_commence_request); + let ack = client + .clone() + .perform_lock(perform_lock_request) + .await? + .into_inner(); + println!("Response ACK from driver={:?}\n", ack); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + // Call the transfer_commence endpoint on the receiver gateway pub async fn call_transfer_commence( relay_host: String, @@ -516,6 +555,12 @@ pub fn create_lock_assertion_receipt_request( return lock_assertion_receipt_request; } +pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> PerformLockRequest { + // TODO: remove hard coded values + let perform_lock_request = PerformLockRequest {}; + return perform_lock_request; +} + pub fn get_satp_requests_local_db(conf: Config) -> Database { let db = Database { db_path: format!( @@ -664,6 +709,11 @@ pub fn get_relay_from_lock_assertion_receipt( return ("localhost".to_string(), "9085".to_string()); } +pub fn get_driver_address_from_ack_commence(ack_commence_request: AckCommenceRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 71fe74b7d0..b5dd91c78f 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -8,17 +8,19 @@ use weaverpb::relay::satp::{ // Internal modules use crate::error::Error; +use crate::relay_proto::parse_address; use crate::services::satp_helper::{ create_ack_error_message, get_request_id_from_transfer_proposal_receipt, log_request_in_local_satp_db, log_request_in_remote_satp_db, }; +use super::helpers::get_driver; // external modules use super::satp_helper::{ create_ack_commence_request, create_lock_assertion_receipt_request, create_lock_assertion_request, create_transfer_commence_request, - create_transfer_proposal_receipt_request, get_relay_from_ack_commence, - get_relay_from_lock_assertion, get_relay_from_transfer_commence, + create_transfer_proposal_receipt_request, get_driver_address_from_ack_commence, + get_relay_from_ack_commence, get_relay_from_lock_assertion, get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, spawn_send_lock_assertion_broadcast_request, @@ -713,23 +715,40 @@ fn send_perform_lock_request( let (relay_host, relay_port) = get_relay_from_ack_commence(ack_commence_request.clone()); let (use_tls, relay_tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let perfrom_lock_request = create_lock_assertion_request(ack_commence_request.clone()); - - spawn_send_perform_lock_request( - perfrom_lock_request, - relay_host, - relay_port, - use_tls, - relay_tlsca_cert_path, - conf, - ); - - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request_id.to_string(), - message: "Ack of the ack commence request".to_string(), - }; - return Ok(reply); + let lock_assertion_request = create_lock_assertion_request(ack_commence_request.clone()); + let driver_address = get_driver_address_from_ack_commence(ack_commence_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); + match result { + Ok(driver_info) => { + spawn_send_perform_lock_request( + driver_info, + ack_commence_request, + lock_assertion_request, + relay_host, + relay_port, + use_tls, + relay_tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the ack commence request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the ack commence request failed. Driver not found {:?}", + e + ), + }); + } + } } fn send_lock_assertion_broadcast_request( From f61d126a509af85b333e4583dd81bd70c20e9532 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Fri, 4 Aug 2023 08:19:22 +0100 Subject: [PATCH 30/59] corrected some variable names --- .../relay/src/services/network_service.rs | 16 ++++----- weaver/core/relay/src/services/satp_helper.rs | 36 +++++++++---------- .../core/relay/src/services/satp_service.rs | 24 ++++++------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 2ae2076a8b..1d253ce9c5 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -597,7 +597,7 @@ impl Network for NetworkService { let (relay_host, relay_port) = get_relay_from_transfer_proposal_claims( transfer_proposal_claims_request.clone(), ); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); // TODO: verify that host and port are valid @@ -607,7 +607,7 @@ impl Network for NetworkService { relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); // Send Ack back to network while request is happening in a thread @@ -809,12 +809,12 @@ fn spawn_send_request( // Iterate through the relay entries in the configuration to find a match let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; - let mut relay_tlsca_cert_path = "".to_string(); + let mut tlsca_cert_path = "".to_string(); for (_relay_name, relay_spec) in relays_table { let relay_uri = relay_spec.clone().try_into::().unwrap(); if relay_host == relay_uri.hostname && relay_port == relay_uri.port { relay_tls = relay_uri.tls; - relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + tlsca_cert_path = relay_uri.tlsca_cert_path; } } @@ -825,7 +825,7 @@ fn spawn_send_request( network_query, request_id.clone(), relay_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), ) .await; println!("Received Ack from remote relay: {:?}\n", result); @@ -948,12 +948,12 @@ fn spawn_send_event_subscription_request( // Iterate through the relay entries in the configuration to find a match let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; - let mut relay_tlsca_cert_path = "".to_string(); + let mut tlsca_cert_path = "".to_string(); for (_relay_name, relay_spec) in relays_table { let relay_uri = relay_spec.clone().try_into::().unwrap(); if relay_host == relay_uri.hostname && relay_port == relay_uri.port { relay_tls = relay_uri.tls; - relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + tlsca_cert_path = relay_uri.tlsca_cert_path; } } @@ -962,7 +962,7 @@ fn spawn_send_event_subscription_request( relay_port, event_subscription, relay_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), ) .await; println!("Received Ack from remote relay: {:?}\n", result); diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 8139d52f5e..ea7258ec2d 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -31,7 +31,7 @@ pub fn spawn_send_transfer_proposal_claims_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { println!( @@ -50,7 +50,7 @@ pub fn spawn_send_transfer_proposal_claims_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), transfer_proposal_claims_request.clone(), ) .await; @@ -67,7 +67,7 @@ pub fn spawn_send_transfer_commence_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { println!( @@ -85,7 +85,7 @@ pub fn spawn_send_transfer_commence_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), transfer_commence_request.clone(), ) .await; @@ -101,7 +101,7 @@ pub fn spawn_send_transfer_proposal_receipt_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { @@ -116,7 +116,7 @@ pub fn spawn_send_transfer_proposal_receipt_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), transfer_proposal_receipt_request.clone(), ) .await; @@ -132,7 +132,7 @@ pub fn spawn_send_ack_commence_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { @@ -145,7 +145,7 @@ pub fn spawn_send_ack_commence_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), ack_commence_request.clone(), ) .await; @@ -163,7 +163,7 @@ pub fn spawn_send_perform_lock_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { @@ -177,10 +177,10 @@ pub fn spawn_send_perform_lock_request( let result = call_perform_lock(driver_info, ack_commence_request).await; match result { Ok(_) => { - println!("Ack Ok from driver\n") + println!("Perform lock request sent to driver\n") } Err(e) => { - println!("Error sending query to driver: {:?}\n", e); + println!("Error sending perform lock request to driver: {:?}\n", e); // TODO: what to do in this case? } } @@ -191,7 +191,7 @@ pub fn spawn_send_perform_lock_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), lock_assertion_request.clone(), ) .await; @@ -208,7 +208,7 @@ pub fn spawn_send_lock_assertion_broadcast_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { @@ -223,7 +223,7 @@ pub fn spawn_send_lock_assertion_broadcast_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), lock_assertion_receipt_request.clone(), ) .await; @@ -247,7 +247,7 @@ async fn call_perform_lock( .perform_lock(perform_lock_request) .await? .into_inner(); - println!("Response ACK from driver={:?}\n", ack); + println!("Response ACK from driver to perform lock {:?}\n", ack); let status = ack::Status::from_i32(ack.status) .ok_or(Error::Simple("Status from Driver error".to_string()))?; match status { @@ -717,15 +717,15 @@ pub fn get_driver_address_from_ack_commence(ack_commence_request: AckCommenceReq pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; - let mut relay_tlsca_cert_path = "".to_string(); + let mut tlsca_cert_path = "".to_string(); for (_relay_name, relay_spec) in relays_table { let relay_uri = relay_spec.clone().try_into::().unwrap(); if relay_host == relay_uri.hostname && relay_port == relay_uri.port { relay_tls = relay_uri.tls; - relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + tlsca_cert_path = relay_uri.tlsca_cert_path; } } - (relay_tls, relay_tlsca_cert_path) + (relay_tls, tlsca_cert_path) } fn create_client_address(relay_host: String, relay_port: String) -> String { diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index b5dd91c78f..a6031eaf9a 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -603,7 +603,7 @@ fn send_transfer_proposal_receipt_request( get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); let (relay_host, relay_port) = get_relay_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let transfer_proposal_receipt_request = create_transfer_proposal_receipt_request(transfer_proposal_claims_request.clone()); @@ -613,7 +613,7 @@ fn send_transfer_proposal_receipt_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -632,7 +632,7 @@ fn send_transfer_commence_request( get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); let (relay_host, relay_port) = get_relay_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let transfer_commence_request = create_transfer_commence_request(transfer_proposal_receipt_request.clone()); @@ -642,7 +642,7 @@ fn send_transfer_commence_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -660,7 +660,7 @@ fn send_ack_commence_request( let request_id = &transfer_commence_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_transfer_commence(transfer_commence_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let ack_commence_request = create_ack_commence_request(transfer_commence_request.clone()); @@ -669,7 +669,7 @@ fn send_ack_commence_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -686,7 +686,7 @@ fn send_lock_assertion_receipt_request( ) -> Result { let request_id = &lock_assertion_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let lock_assertion_receipt_request = create_lock_assertion_receipt_request(lock_assertion_request.clone()); @@ -696,7 +696,7 @@ fn send_lock_assertion_receipt_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -713,7 +713,7 @@ fn send_perform_lock_request( ) -> Result { let request_id = &ack_commence_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_ack_commence(ack_commence_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let lock_assertion_request = create_lock_assertion_request(ack_commence_request.clone()); let driver_address = get_driver_address_from_ack_commence(ack_commence_request.clone()); @@ -728,7 +728,7 @@ fn send_perform_lock_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -757,7 +757,7 @@ fn send_lock_assertion_broadcast_request( ) -> Result { let request_id = &lock_assertion_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); let lock_assertion_receipt_request = create_lock_assertion_receipt_request(lock_assertion_request.clone()); @@ -767,7 +767,7 @@ fn send_lock_assertion_broadcast_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { From a26af14736eee7fc252c10d5c99e58c4f1f2f8a4 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Wed, 9 Aug 2023 10:26:33 +0100 Subject: [PATCH 31/59] Added the endpoints corresponding to the steps 3.1 to 3.9 --- .../protos-rs/pkg/src/generated/relay.satp.rs | 398 ++++++++++++ weaver/common/protos/relay/satp.proto | 40 ++ weaver/core/relay/src/services/satp_helper.rs | 363 ++++++++++- .../core/relay/src/services/satp_service.rs | 571 +++++++++++++++++- 4 files changed, 1360 insertions(+), 12 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index 743a57a40b..32e96b36e1 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -152,6 +152,61 @@ pub struct LockAssertionReceiptRequest { #[prost(string, tag = "8")] pub server_signature: ::prost::alloc::string::String, } +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommitPrepareRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommitReadyRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommitFinalAssertionRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AckFinalReceiptRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransferCompletedRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} /// Generated client implementations. pub mod satp_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] @@ -366,6 +421,116 @@ pub mod satp_client { ); self.inner.unary(request.into_request(), path, codec).await } + pub async fn commit_prepare( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/CommitPrepare", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn commit_ready( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/CommitReady", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn commit_final_assertion( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/CommitFinalAssertion", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn ack_final_receipt( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/AckFinalReceipt", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn transfer_completed( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/TransferCompleted", + ); + self.inner.unary(request.into_request(), path, codec).await + } } } /// Generated server implementations. @@ -430,6 +595,41 @@ pub mod satp_server { tonic::Response, tonic::Status, >; + async fn commit_prepare( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn commit_ready( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn commit_final_assertion( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn ack_final_receipt( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn transfer_completed( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct SatpServer { @@ -730,6 +930,204 @@ pub mod satp_server { }; Box::pin(fut) } + "/relay.satp.SATP/CommitPrepare" => { + #[allow(non_camel_case_types)] + struct CommitPrepareSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for CommitPrepareSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).commit_prepare(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommitPrepareSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/CommitReady" => { + #[allow(non_camel_case_types)] + struct CommitReadySvc(pub Arc); + impl tonic::server::UnaryService + for CommitReadySvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).commit_ready(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommitReadySvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/CommitFinalAssertion" => { + #[allow(non_camel_case_types)] + struct CommitFinalAssertionSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for CommitFinalAssertionSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).commit_final_assertion(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommitFinalAssertionSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/AckFinalReceipt" => { + #[allow(non_camel_case_types)] + struct AckFinalReceiptSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for AckFinalReceiptSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).ack_final_receipt(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = AckFinalReceiptSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/TransferCompleted" => { + #[allow(non_camel_case_types)] + struct TransferCompletedSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for TransferCompletedSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).transfer_completed(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = TransferCompletedSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( diff --git a/weaver/common/protos/relay/satp.proto b/weaver/common/protos/relay/satp.proto index 66d2bf7073..595f91d7fb 100644 --- a/weaver/common/protos/relay/satp.proto +++ b/weaver/common/protos/relay/satp.proto @@ -38,6 +38,16 @@ service SATP { // The receiver gateway sends a LockAssertionReceipt request to the sender gateway to indicate acceptance // of the claim(s) delivered by the sender gateway in the previous message rpc LockAssertionReceipt(LockAssertionReceiptRequest) returns (common.ack.Ack) {}; + + rpc CommitPrepare(CommitPrepareRequest) returns (common.ack.Ack) {}; + + rpc CommitReady(CommitReadyRequest) returns (common.ack.Ack) {}; + + rpc CommitFinalAssertion(CommitFinalAssertionRequest) returns (common.ack.Ack) {}; + + rpc AckFinalReceipt(AckFinalReceiptRequest) returns (common.ack.Ack) {}; + + rpc TransferCompleted(TransferCompletedRequest) returns (common.ack.Ack) {}; } message TransferProposalClaimsRequest { @@ -118,4 +128,34 @@ message LockAssertionReceiptRequest { string hash_prev_message = 6; string server_transfer_number = 7; string server_signature = 8; +} + +message CommitPrepareRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message CommitReadyRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message CommitFinalAssertionRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message AckFinalReceiptRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message TransferCompletedRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; } \ No newline at end of file diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index ea7258ec2d..51141e332a 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -10,8 +10,9 @@ use weaverpb::driver::driver::PerformLockRequest; use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ - AckCommenceRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, - TransferProposalClaimsRequest, TransferProposalReceiptRequest, + AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, + CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, + TransferCompletedRequest, TransferProposalClaimsRequest, TransferProposalReceiptRequest, }; use crate::db::Database; @@ -235,6 +236,178 @@ pub fn spawn_send_lock_assertion_broadcast_request( }); } +// Sends a request to the receiving gateway +pub fn spawn_send_commit_prepare_request( + commit_prepare_request: CommitPrepareRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + println!( + "Sending commit prepare request to receiver gateway: {:?}:{:?}", + relay_host, relay_port + ); + // Spawning new thread to make the call_commit_prepare to receiver gateway + tokio::spawn(async move { + let request_id = commit_prepare_request.session_id.to_string(); + println!( + "Sending commit prepare request to receiver gateway: Request ID = {:?}", + request_id + ); + let result = call_commit_prepare( + relay_host, + relay_port, + use_tls, + tlsca_cert_path.to_string(), + commit_prepare_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_create_asset_request( + commit_ready_request: CommitReadyRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = commit_ready_request.session_id.to_string(); + println!( + "Creating the asset corresponding to the commit ready request {:?}", + request_id + ); + // TODO + // Creating the asset in the target network + // Subscribe to the status event + // Once the message is broadcast, call the call_commit_ready endpoint + // log the results + let result = call_commit_ready( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + commit_ready_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = commit_ready_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_assign_asset_request( + ack_final_receipt_request: AckFinalReceiptRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = ack_final_receipt_request.session_id.to_string(); + println!( + "Assigning the asset corresponding to the commit final assertion request {:?}", + request_id + ); + // TODO + // Assigning the asset in the target network + // Once the asset is assigned, call the call_ack_final_receipt endpoint + // log the results + let result = call_ack_final_receipt( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + ack_final_receipt_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = ack_final_receipt_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_ack_final_receipt_broadcast_request( + transfer_completed_request: TransferCompletedRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = transfer_completed_request.session_id.to_string(); + println!( + "Acknowledge final receipt broadcast of the transfer completed request {:?}", + request_id + ); + // TODO + // Ack final receipt broadcast + // Once the broadcast is done, call the call_transfer_completed endpoint + // log the results + let result = call_transfer_completed( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + transfer_completed_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = transfer_completed_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_extinguish_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = commit_final_assertion_request.session_id.to_string(); + println!( + "Extinguishing the asset corresponding to the commit final assertion request {:?}", + request_id + ); + // TODO + // Assigning the asset in the target network + // Once the asset is assigned, call the call_ack_final_receipt endpoint + // log the results + let result = call_commit_final_assertion_receipt( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + commit_final_assertion_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = commit_final_assertion_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + async fn call_perform_lock( driver_info: Driver, ack_commence_request: AckCommenceRequest, @@ -379,6 +552,106 @@ pub async fn call_lock_assertion_receipt( Ok(response) } +// Call the call_commit_ready endpoint on the sending gateway +pub async fn call_commit_prepare( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + commit_prepare_request: CommitPrepareRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the commit prepare request: {:?}", + commit_prepare_request.clone() + ); + let response = satp_client + .commit_prepare(commit_prepare_request.clone()) + .await?; + Ok(response) +} + +// Call the call_commit_ready endpoint on the sending gateway +pub async fn call_commit_ready( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + commit_ready_request: CommitReadyRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the commit ready request: {:?}", + commit_ready_request.clone() + ); + let response = satp_client + .commit_ready(commit_ready_request.clone()) + .await?; + Ok(response) +} + +// Call the call_ack_final_receipt endpoint on the sending gateway +pub async fn call_ack_final_receipt( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + ack_final_receipt_request: AckFinalReceiptRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the ack final receipt request: {:?}", + ack_final_receipt_request.clone() + ); + let response = satp_client + .ack_final_receipt(ack_final_receipt_request.clone()) + .await?; + Ok(response) +} + +// Call the call_transfer_completed endpoint on the sending gateway +pub async fn call_transfer_completed( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + transfer_completed_request: TransferCompletedRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the transfer completed request: {:?}", + transfer_completed_request.clone() + ); + let response = satp_client + .transfer_completed(transfer_completed_request.clone()) + .await?; + Ok(response) +} + +// Call the call_commit_final_assertion_receipt endpoint on the sending gateway +pub async fn call_commit_final_assertion_receipt( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the commit final assertion request: {:?}", + commit_final_assertion_request.clone() + ); + let response = satp_client + .commit_final_assertion(commit_final_assertion_request.clone()) + .await?; + Ok(response) +} + pub fn log_request_result_in_local_satp_db( request_id: &String, result: Result, Box>, @@ -555,6 +828,66 @@ pub fn create_lock_assertion_receipt_request( return lock_assertion_receipt_request; } +pub fn create_commit_prepare_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> CommitPrepareRequest { + // TODO: remove hard coded values + let commit_prepare_request = CommitPrepareRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_prepare_request; +} + +pub fn create_commit_ready_request( + commit_prepare_request: CommitPrepareRequest, +) -> CommitReadyRequest { + // TODO: remove hard coded values + let commit_ready_request = CommitReadyRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_ready_request; +} + +pub fn create_commit_final_assertion_request( + commit_ready_request: CommitReadyRequest, +) -> CommitFinalAssertionRequest { + // TODO: remove hard coded values + let commit_final_assertion_request = CommitFinalAssertionRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_final_assertion_request; +} + +pub fn create_ack_final_receipt_request( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> AckFinalReceiptRequest { + // TODO: remove hard coded values + let ack_final_receipt_request = AckFinalReceiptRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return ack_final_receipt_request; +} + +pub fn create_transfer_completed_request( + ack_final_receipt_request: AckFinalReceiptRequest, +) -> TransferCompletedRequest { + // TODO: remove hard coded values + let transfer_completed_request = TransferCompletedRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return transfer_completed_request; +} + pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> PerformLockRequest { // TODO: remove hard coded values let perform_lock_request = PerformLockRequest {}; @@ -709,6 +1042,32 @@ pub fn get_relay_from_lock_assertion_receipt( return ("localhost".to_string(), "9085".to_string()); } +pub fn get_relay_from_commit_prepare( + commit_prepare_request: CommitPrepareRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_commit_ready(commit_ready_request: CommitReadyRequest) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_commit_final_assertion( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_ack_final_receipt( + ack_final_receipt_request: AckFinalReceiptRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + pub fn get_driver_address_from_ack_commence(ack_commence_request: AckCommenceRequest) -> String { // TODO return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index a6031eaf9a..f154cce560 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -2,8 +2,9 @@ use weaverpb::common::ack::{ack, Ack}; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{ - AckCommenceRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, - TransferProposalClaimsRequest, TransferProposalReceiptRequest, + AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, + CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, + TransferCompletedRequest, TransferProposalClaimsRequest, TransferProposalReceiptRequest, }; // Internal modules @@ -17,15 +18,22 @@ use crate::services::satp_helper::{ use super::helpers::get_driver; // external modules use super::satp_helper::{ - create_ack_commence_request, create_lock_assertion_receipt_request, + create_ack_commence_request, create_ack_final_receipt_request, + create_commit_final_assertion_request, create_commit_prepare_request, + create_commit_ready_request, create_lock_assertion_receipt_request, create_lock_assertion_request, create_transfer_commence_request, - create_transfer_proposal_receipt_request, get_driver_address_from_ack_commence, - get_relay_from_ack_commence, get_relay_from_lock_assertion, get_relay_from_transfer_commence, + create_transfer_completed_request, create_transfer_proposal_receipt_request, + get_driver_address_from_ack_commence, get_relay_from_ack_commence, + get_relay_from_ack_final_receipt, get_relay_from_commit_final_assertion, + get_relay_from_commit_prepare, get_relay_from_commit_ready, get_relay_from_lock_assertion, + get_relay_from_lock_assertion_receipt, get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, - spawn_send_ack_commence_request, spawn_send_lock_assertion_broadcast_request, - spawn_send_perform_lock_request, spawn_send_transfer_commence_request, - spawn_send_transfer_proposal_receipt_request, + spawn_send_ack_commence_request, spawn_send_ack_final_receipt_broadcast_request, + spawn_send_assign_asset_request, spawn_send_commit_prepare_request, + spawn_send_create_asset_request, spawn_send_extinguish_request, + spawn_send_lock_assertion_broadcast_request, spawn_send_perform_lock_request, + spawn_send_transfer_commence_request, spawn_send_transfer_proposal_receipt_request, }; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; @@ -341,6 +349,248 @@ impl Satp for SatpService { } } } + + async fn commit_prepare( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got commit prepare request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let commit_prepare_request = request.into_inner().clone(); + let request_id = commit_prepare_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &commit_prepare_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored CommitPrepareRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing CommitPrepareRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_commit_prepare_request(commit_prepare_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!("Sending Ack of commit prepare request back: {:?}\n", reply); + reply + } + Err(e) => { + let error_message = "Commit prepare failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn commit_ready( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got commit ready request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let commit_ready_request = request.into_inner().clone(); + let request_id = commit_ready_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &commit_ready_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored CommitReadyRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing CommitReadyRequest in local satp_db for request_id".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_commit_ready_request(commit_ready_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!("Sending Ack of commit ready request back: {:?}\n", reply); + reply + } + Err(e) => { + let error_message = "Commit ready failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn commit_final_assertion( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got commit final assertion request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let commit_final_assertion_request = request.into_inner().clone(); + let request_id = commit_final_assertion_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = log_request_in_local_satp_db( + &request_id, + &commit_final_assertion_request, + conf.clone(), + ); + match request_logged { + Ok(_) => { + println!( + "Successfully stored CommitFinalAssertionRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing CommitFinalAssertionRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_commit_final_assertion_request(commit_final_assertion_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of commit final assertion request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Commit final assertion failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn ack_final_receipt( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got commit final assertion request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let ack_final_receipt_request = request.into_inner().clone(); + let request_id = ack_final_receipt_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &ack_final_receipt_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored AckFinalReceiptRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing AckFinalReceiptRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_ack_final_receipt_request(ack_final_receipt_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of ack final receipt request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Ack final receipt failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn transfer_completed( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got commit final assertion request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let transfer_completed_request = request.into_inner().clone(); + let request_id = transfer_completed_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &transfer_completed_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored TransferCompletedRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing TransferCompletedRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Transfer Completed request".to_string(), + }; + return Ok(Response::new(reply)); + } } pub fn process_transfer_proposal_claims_request( @@ -595,6 +845,147 @@ pub fn process_lock_assertion_receipt_request( } } +pub fn process_commit_prepare_request( + commit_prepare_request: CommitPrepareRequest, + conf: config::Config, +) -> Result { + let request_id = commit_prepare_request.session_id.to_string(); + let is_valid_request = is_valid_commit_prepare_request(commit_prepare_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The commit prepare request is valid\n"); + match send_commit_ready_request(commit_prepare_request, conf) { + Ok(ack) => { + println!("Ack commit prepare request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: commit prepare request failed. {:?}", e), + }); + } + } + } else { + println!("The commit prepare request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The commit prepare request is invalid".to_string(), + }); + } +} + +pub fn process_commit_ready_request( + commit_ready_request: CommitReadyRequest, + conf: config::Config, +) -> Result { + let request_id = commit_ready_request.session_id.to_string(); + let is_valid_request = is_valid_commit_ready_request(commit_ready_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The commit ready request is valid\n"); + match send_commit_final_assertion_request(commit_ready_request, conf) { + Ok(ack) => { + println!("Ack commit ready request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: commit ready request failed. {:?}", e), + }); + } + } + } else { + println!("The commit ready request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The commit ready request is invalid".to_string(), + }); + } +} + +pub fn process_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + conf: config::Config, +) -> Result { + let request_id = commit_final_assertion_request.session_id.to_string(); + let is_valid_request = + is_valid_commit_final_assertion_request(commit_final_assertion_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The commit final assertion request is valid\n"); + match send_ack_final_receipt_request(commit_final_assertion_request, conf) { + Ok(ack) => { + println!("Ack commit final assertion request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: commit final assertion request failed. {:?}", e), + }); + } + } + } else { + println!("The commit final assertion request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The commit final assertion request is invalid".to_string(), + }); + } +} + +pub fn process_ack_final_receipt_request( + ack_final_receipt_request: AckFinalReceiptRequest, + conf: config::Config, +) -> Result { + let request_id = ack_final_receipt_request.session_id.to_string(); + let is_valid_request = is_valid_ack_final_receipt_request(ack_final_receipt_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The ack final receipt request is valid\n"); + match send_transfer_completed_request(ack_final_receipt_request, conf) { + Ok(ack) => { + println!("Ack ack final receipt request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: ack final receipt request failed. {:?}", e), + }); + } + } + } else { + println!("The ack final receipt request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The ack final receipt request is invalid".to_string(), + }); + } +} + fn send_transfer_proposal_receipt_request( transfer_proposal_claims_request: TransferProposalClaimsRequest, conf: config::Config, @@ -782,12 +1173,143 @@ fn send_commit_prepare_request( lock_assertion_receipt_request: LockAssertionReceiptRequest, conf: config::Config, ) -> Result { - // TODO let request_id = &lock_assertion_receipt_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_lock_assertion_receipt(lock_assertion_receipt_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let commit_prepare_request = + create_commit_prepare_request(lock_assertion_receipt_request.clone()); + + spawn_send_commit_prepare_request( + commit_prepare_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), - message: "Ack of the Lock Assertion Receipt request".to_string(), + message: "Ack of the Lock Assertion request".to_string(), + }; + return Ok(reply); +} + +fn send_commit_ready_request( + commit_prepare_request: CommitPrepareRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_prepare_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let commit_ready_request = create_commit_ready_request(commit_prepare_request.clone()); + + spawn_send_create_asset_request( + commit_ready_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_commit_final_assertion_request( + commit_ready_request: CommitReadyRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_ready_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_commit_ready(commit_ready_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let commit_final_assertion_request = + create_commit_final_assertion_request(commit_ready_request.clone()); + + spawn_send_extinguish_request( + commit_final_assertion_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_ack_final_receipt_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_final_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_commit_final_assertion(commit_final_assertion_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let ack_final_receipt_request = + create_ack_final_receipt_request(commit_final_assertion_request.clone()); + + spawn_send_assign_asset_request( + ack_final_receipt_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_transfer_completed_request( + ack_final_receipt_request: AckFinalReceiptRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &ack_final_receipt_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let transfer_completed_request = + create_transfer_completed_request(ack_final_receipt_request.clone()); + + spawn_send_ack_final_receipt_broadcast_request( + transfer_completed_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), }; return Ok(reply); } @@ -827,3 +1349,32 @@ fn is_valid_lock_assertion_receipt_request( //TODO true } + +fn is_valid_commit_prepare_request(commit_prepare_request: CommitPrepareRequest) -> bool { + //TODO + true +} + +fn is_valid_commit_ready_request(commit_ready_request: CommitReadyRequest) -> bool { + //TODO + true +} + +fn is_valid_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> bool { + //TODO + true +} + +fn is_valid_ack_final_receipt_request(ack_final_receipt_request: AckFinalReceiptRequest) -> bool { + //TODO + true +} + +fn is_valid_transfer_completed_request( + transfer_completed_request: TransferCompletedRequest, +) -> bool { + //TODO + true +} From 3c129592d1958435ab0ff4a40273bf48cf842db9 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 14 Aug 2023 10:48:31 +0100 Subject: [PATCH 32/59] Implemented the step 2.1B so that the driver call the gateway to update the asset status --- .../pkg/src/generated/driver.driver.rs | 5 +- .../protos-rs/pkg/src/generated/relay.satp.rs | 90 +++++++++ weaver/common/protos/driver/driver.proto | 4 +- weaver/common/protos/relay/satp.proto | 13 ++ weaver/core/relay/driver/driver.rs | 177 ++++++++++++++--- weaver/core/relay/src/services/satp_helper.rs | 69 ++++--- .../core/relay/src/services/satp_service.rs | 180 +++++++++++++----- 7 files changed, 432 insertions(+), 106 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs index 188e49d79c..efa1273e38 100644 --- a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs +++ b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs @@ -15,7 +15,10 @@ pub struct WriteExternalStateMessage { #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct PerformLockRequest {} +pub struct PerformLockRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} /// Generated client implementations. pub mod driver_communication_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index 32e96b36e1..c1b94e14b9 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -107,6 +107,27 @@ pub struct AckCommenceRequest { #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct SendAssetStatusRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub hash_prev_message: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub server_transfer_number: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub server_signature: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct LockAssertionRequest { #[prost(string, tag = "1")] pub message_type: ::prost::alloc::string::String, @@ -372,6 +393,28 @@ pub mod satp_client { ); self.inner.unary(request.into_request(), path, codec).await } + pub async fn send_asset_status( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/SendAssetStatus", + ); + self.inner.unary(request.into_request(), path, codec).await + } /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway /// declaring that the asset in question has been locked or escrowed by the sender gateway in /// the origin network (e.g. to prevent double spending) @@ -576,6 +619,13 @@ pub mod satp_server { tonic::Response, tonic::Status, >; + async fn send_asset_status( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway /// declaring that the asset in question has been locked or escrowed by the sender gateway in /// the origin network (e.g. to prevent double spending) @@ -850,6 +900,46 @@ pub mod satp_server { }; Box::pin(fut) } + "/relay.satp.SATP/SendAssetStatus" => { + #[allow(non_camel_case_types)] + struct SendAssetStatusSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for SendAssetStatusSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).send_asset_status(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = SendAssetStatusSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/relay.satp.SATP/LockAssertion" => { #[allow(non_camel_case_types)] struct LockAssertionSvc(pub Arc); diff --git a/weaver/common/protos/driver/driver.proto b/weaver/common/protos/driver/driver.proto index a11cae23f2..6f0c0ccce0 100644 --- a/weaver/common/protos/driver/driver.proto +++ b/weaver/common/protos/driver/driver.proto @@ -20,7 +20,9 @@ message WriteExternalStateMessage { common.events.ContractTransaction ctx = 2; } -message PerformLockRequest {} +message PerformLockRequest { + string session_id = 1; +} service DriverCommunication { // Data Sharing diff --git a/weaver/common/protos/relay/satp.proto b/weaver/common/protos/relay/satp.proto index 595f91d7fb..d7dd1b63c4 100644 --- a/weaver/common/protos/relay/satp.proto +++ b/weaver/common/protos/relay/satp.proto @@ -30,6 +30,8 @@ service SATP { // Stage 2 endpoints + rpc SendAssetStatus(SendAssetStatusRequest) returns (common.ack.Ack) {}; + // The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway // declaring that the asset in question has been locked or escrowed by the sender gateway in // the origin network (e.g. to prevent double spending) @@ -105,6 +107,17 @@ message AckCommenceRequest { string server_signature = 8; } +message SendAssetStatusRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_prev_message = 6; + string server_transfer_number = 7; + string server_signature = 8; +} + message LockAssertionRequest { string message_type = 1; string session_id = 2; diff --git a/weaver/core/relay/driver/driver.rs b/weaver/core/relay/driver/driver.rs index 7e8721ccc7..d3fa64f79b 100644 --- a/weaver/core/relay/driver/driver.rs +++ b/weaver/core/relay/driver/driver.rs @@ -6,11 +6,13 @@ // Internal modules use weaverpb::common::ack::{ack, Ack}; -use weaverpb::common::query::Query; use weaverpb::common::events::EventSubscription; -use weaverpb::common::state::{view_payload, Meta, meta, ViewPayload, View}; -use weaverpb::driver::driver::driver_communication_server::{DriverCommunication, DriverCommunicationServer}; -use weaverpb::driver::driver::{WriteExternalStateMessage, PerformLockRequest}; +use weaverpb::common::query::Query; +use weaverpb::common::state::{meta, view_payload, Meta, View, ViewPayload}; +use weaverpb::driver::driver::driver_communication_server::{ + DriverCommunication, DriverCommunicationServer, +}; +use weaverpb::driver::driver::{PerformLockRequest, WriteExternalStateMessage}; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; @@ -22,8 +24,10 @@ use std::net::ToSocketAddrs; use std::thread::sleep; use std::time; use tokio::sync::RwLock; -use tonic::transport::{Identity, Server, ServerTlsConfig, Certificate, Channel, ClientTlsConfig}; +use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity, Server, ServerTlsConfig}; use tonic::{Request, Response, Status}; +use weaverpb::relay::satp::satp_client::SatpClient; +use weaverpb::relay::satp::SendAssetStatusRequest; pub struct DriverCommunicationService { pub config_lock: RwLock, @@ -42,7 +46,7 @@ impl DriverCommunication for DriverCommunicationService { println!("Got a request from {:?}", request.remote_addr()); let query = request.into_inner().clone(); let request_id = query.request_id.to_string(); - + let relays_table = self .config_lock .read() @@ -52,7 +56,9 @@ impl DriverCommunication for DriverCommunicationService { let relay_uri = relays_table .get(&query.requesting_relay.to_string()) .expect("Requesting relay not found in config file relays table"); - let uri = relay_uri.clone().try_into::() + let uri = relay_uri + .clone() + .try_into::() .expect("Syntax for relays table in config file not correct"); let relay_port = uri.port.to_string(); @@ -60,7 +66,7 @@ impl DriverCommunication for DriverCommunicationService { let use_tls = uri.tls; let tlsca_cert_path = uri.tlsca_cert_path.to_string(); let client_addr = format!("http://{}:{}", relay_hostname, relay_port); - + if use_tls { let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); let ca = Certificate::from_pem(pem); @@ -69,8 +75,13 @@ impl DriverCommunication for DriverCommunicationService { .ca_certificate(ca) .domain_name(relay_hostname); - let channel = Channel::from_shared(client_addr.to_string()).unwrap() - .tls_config(tls).expect(&format!("Error in TLS configuration for client: {}", client_addr.to_string())) + let channel = Channel::from_shared(client_addr.to_string()) + .unwrap() + .tls_config(tls) + .expect(&format!( + "Error in TLS configuration for client: {}", + client_addr.to_string() + )) .connect() .await .unwrap(); @@ -99,8 +110,14 @@ impl DriverCommunication for DriverCommunicationService { return Ok(Response::new(reply)); } - async fn subscribe_event(&self, request: Request) -> Result, Status> { - println!("Driver: Got a event subscription request from {:?}", request.remote_addr()); + async fn subscribe_event( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Driver: Got a event subscription request from {:?}", + request.remote_addr() + ); let into_inner = request.into_inner().clone(); let query = into_inner.query.clone().expect(""); let request_id = query.clone().request_id.to_string(); @@ -114,9 +131,11 @@ impl DriverCommunication for DriverCommunicationService { let relay_uri = relays_table .get(&query.requesting_relay.to_string()) .expect("Requesting relay not found in config file relays table"); - let uri = relay_uri.clone().try_into::() + let uri = relay_uri + .clone() + .try_into::() .expect("Syntax for relays table in config file not correct"); - + let relay_port = uri.port.to_string(); let relay_hostname = uri.hostname.to_string(); let use_tls = uri.tls; @@ -131,8 +150,13 @@ impl DriverCommunication for DriverCommunicationService { .ca_certificate(ca) .domain_name(relay_hostname); - let channel = Channel::from_shared(client_addr.to_string()).unwrap() - .tls_config(tls).expect(&format!("Error in TLS configuration for client: {}", client_addr.to_string())) + let channel = Channel::from_shared(client_addr.to_string()) + .unwrap() + .tls_config(tls) + .expect(&format!( + "Error in TLS configuration for client: {}", + client_addr.to_string() + )) .connect() .await .unwrap(); @@ -161,7 +185,10 @@ impl DriverCommunication for DriverCommunicationService { return Ok(Response::new(reply)); } - async fn request_signed_event_subscription_query(&self, request: Request) -> Result, Status> { + async fn request_signed_event_subscription_query( + &self, + request: Request, + ) -> Result, Status> { let received_query = request.into_inner().clone().query.expect("Err"); let signed_query: Query = Query { policy: received_query.policy, @@ -177,7 +204,10 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(signed_query)); } - async fn write_external_state(&self, request: Request) -> Result, Status> { + async fn write_external_state( + &self, + request: Request, + ) -> Result, Status> { let view_payload = request.into_inner().view_payload.expect("Error"); let request_id = view_payload.clone().request_id.to_string(); match view_payload.state { @@ -198,7 +228,7 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(reply)); } - } + }, None => {} } let reply_error = Ack { @@ -208,11 +238,72 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(reply_error)); } - - async fn perform_lock(&self, request: Request) -> Result, Status> { + + async fn perform_lock( + &self, + request: Request, + ) -> Result, Status> { println!("Got a request from {:?}", request.remote_addr()); + let perform_lock_request = request.into_inner().clone(); println!("The asset has been locked"); - let request_id = "to_do".to_string(); + let request_id = perform_lock_request.session_id.to_string(); + + let relays_table = self + .config_lock + .read() + .await + .get_table("relays") + .expect("No relays table in config file"); + let requesting_relay = get_relay_from_perform_lock(perform_lock_request); + let relay_uri = relays_table + .get(&requesting_relay.to_string()) + .expect("Requesting relay not found in config file relays table"); + let uri = relay_uri + .clone() + .try_into::() + .expect("Syntax for relays table in config file not correct"); + + let relay_port = uri.port.to_string(); + let relay_hostname = uri.hostname.to_string(); + let use_tls = uri.tls; + let tlsca_cert_path = uri.tlsca_cert_path.to_string(); + let client_addr = format!("http://{}:{}", relay_hostname, relay_port); + + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(relay_hostname); + + let channel = Channel::from_shared(client_addr.to_string()) + .unwrap() + .tls_config(tls) + .expect(&format!( + "Error in TLS configuration for client: {}", + client_addr.to_string() + )) + .connect() + .await + .unwrap(); + + let client = SatpClient::new(channel); + send_driver_mock_send_asset_status_helper(client, request_id.to_string()); + } else { + let client_result = SatpClient::connect(client_addr).await; + match client_result { + Ok(client) => { + // Sends Mocked payload back. + send_driver_mock_send_asset_status_helper(client, request_id.to_string()); + } + Err(e) => { + // TODO: Add better error handling (Attempt a few times?) + panic!("Failed to connect to client. Error: {}", e.to_string()); + } + } + } + let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id, @@ -222,6 +313,11 @@ impl DriverCommunication for DriverCommunicationService { } } +pub fn get_relay_from_perform_lock(perform_lock_request: PerformLockRequest) -> String { + // TODO + return "Dummy_Relay".to_string(); +} + fn send_driver_mock_state_helper(client: DataTransferClient, request_id: String) { tokio::spawn(async move { let my_time = time::Duration::from_millis(3000); @@ -232,7 +328,7 @@ fn send_driver_mock_state_helper(client: DataTransferClient, request_id timestamp: "I am time".to_string(), proof_type: "I am proof".to_string(), serialization_format: "Proto".to_string(), - protocol: meta::Protocol::Fabric as i32 + protocol: meta::Protocol::Fabric as i32, }), data: "This is a mocked payload".as_bytes().to_vec(), })), @@ -243,7 +339,10 @@ fn send_driver_mock_state_helper(client: DataTransferClient, request_id println!("Ack from remote relay={:?}", response); }); } -fn send_driver_mock_subscription_state_helper(client: EventSubscribeClient, request_id: String) { +fn send_driver_mock_subscription_state_helper( + client: EventSubscribeClient, + request_id: String, +) { tokio::spawn(async move { let my_time = time::Duration::from_millis(3000); sleep(my_time); @@ -258,6 +357,30 @@ fn send_driver_mock_subscription_state_helper(client: EventSubscribeClient, request_id: String) { + tokio::spawn(async move { + let my_time = time::Duration::from_millis(3000); + sleep(my_time); + + let send_asset_status_request = SendAssetStatusRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + hash_prev_message: "hash_prev_message1".to_string(), + server_transfer_number: "server_transfer_number1".to_string(), + server_signature: "server_signature1".to_string(), + }; + println!("Sending send asset status request to remote gateway ..."); + let response = client + .clone() + .send_asset_status(send_asset_status_request) + .await; + println!("Ack from remote relay={:?}", response); + }); +} + #[tokio::main] async fn main() -> Result<(), Box> { // NOTE: This will need cleaning up @@ -294,7 +417,7 @@ async fn main() -> Result<(), Box> { .to_socket_addrs()? .next() .expect("Port number is potentially invalid. Unable to create SocketAddr"); - + let driver = DriverCommunicationService { config_lock: RwLock::new(settings.clone()), }; @@ -309,11 +432,11 @@ async fn main() -> Result<(), Box> { .tls_config(ServerTlsConfig::new().identity(identity))? .add_service(DriverCommunicationServer::new(driver)); server.serve(addr).await?; - } else { println!("DriverServer listening on {}", addr); // Spins up two gRPC services in a tonic server. One for relay to relay and one for network to relay communication. - let server = Server::builder().add_service(DriverCommunicationServer::new(driver)); + let server = + Server::builder().add_service(DriverCommunicationServer::new(driver)); server.serve(addr).await?; } } diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 51141e332a..fe1a56d25b 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -11,8 +11,9 @@ use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, - CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, - TransferCompletedRequest, TransferProposalClaimsRequest, TransferProposalReceiptRequest, + CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, SendAssetStatusRequest, + TransferCommenceRequest, TransferCompletedRequest, TransferProposalClaimsRequest, + TransferProposalReceiptRequest, }; use crate::db::Database; @@ -160,15 +161,9 @@ pub fn spawn_send_ack_commence_request( pub fn spawn_send_perform_lock_request( driver_info: Driver, ack_commence_request: AckCommenceRequest, - lock_assertion_request: LockAssertionRequest, - relay_host: String, - relay_port: String, - use_tls: bool, - tlsca_cert_path: String, - conf: Config, ) { tokio::spawn(async move { - let request_id = lock_assertion_request.session_id.to_string(); + let request_id = ack_commence_request.session_id.to_string(); println!( "Locking the asset of the lock assertion request id: {:?}", request_id @@ -185,22 +180,6 @@ pub fn spawn_send_perform_lock_request( // TODO: what to do in this case? } } - - // TODO: Subscribe to the status event - // Once the asset is locked, call the lock_assertion endpoint - let result = call_lock_assertion( - relay_host, - relay_port, - use_tls, - tlsca_cert_path.to_string(), - lock_assertion_request.clone(), - ) - .await; - - println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway - let request_id = lock_assertion_request.session_id.to_string(); - log_request_result_in_local_satp_db(&request_id, result, conf); }); } @@ -236,6 +215,33 @@ pub fn spawn_send_lock_assertion_broadcast_request( }); } +pub fn spawn_send_lock_assertion_request( + lock_assertion_request: LockAssertionRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = lock_assertion_request.session_id.to_string(); + println!("Sending the lock assertion request {:?}", request_id); + let result = call_lock_assertion( + relay_host, + relay_port, + use_tls, + tlsca_cert_path.to_string(), + lock_assertion_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = lock_assertion_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + // Sends a request to the receiving gateway pub fn spawn_send_commit_prepare_request( commit_prepare_request: CommitPrepareRequest, @@ -792,7 +798,7 @@ pub fn create_ack_commence_request( } pub fn create_lock_assertion_request( - ack_commence_request: AckCommenceRequest, + send_asset_status_request: SendAssetStatusRequest, ) -> LockAssertionRequest { // TODO: remove hard coded values let lock_assertion_request = LockAssertionRequest { @@ -890,7 +896,9 @@ pub fn create_transfer_completed_request( pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> PerformLockRequest { // TODO: remove hard coded values - let perform_lock_request = PerformLockRequest {}; + let perform_lock_request = PerformLockRequest { + session_id: "session_id1".to_string(), + }; return perform_lock_request; } @@ -1068,6 +1076,13 @@ pub fn get_relay_from_ack_final_receipt( return ("localhost".to_string(), "9085".to_string()); } +pub fn get_relay_from_send_asset_status( + send_asset_status_request: SendAssetStatusRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + pub fn get_driver_address_from_ack_commence(ack_commence_request: AckCommenceRequest) -> String { // TODO return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index f154cce560..0d95acab03 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -3,8 +3,9 @@ use weaverpb::common::ack::{ack, Ack}; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{ AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, - CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, - TransferCompletedRequest, TransferProposalClaimsRequest, TransferProposalReceiptRequest, + CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, SendAssetStatusRequest, + TransferCommenceRequest, TransferCompletedRequest, TransferProposalClaimsRequest, + TransferProposalReceiptRequest, }; // Internal modules @@ -26,13 +27,14 @@ use super::satp_helper::{ get_driver_address_from_ack_commence, get_relay_from_ack_commence, get_relay_from_ack_final_receipt, get_relay_from_commit_final_assertion, get_relay_from_commit_prepare, get_relay_from_commit_ready, get_relay_from_lock_assertion, - get_relay_from_lock_assertion_receipt, get_relay_from_transfer_commence, - get_relay_from_transfer_proposal_claims, get_relay_from_transfer_proposal_receipt, - get_relay_params, get_request_id_from_transfer_proposal_claims, - spawn_send_ack_commence_request, spawn_send_ack_final_receipt_broadcast_request, - spawn_send_assign_asset_request, spawn_send_commit_prepare_request, - spawn_send_create_asset_request, spawn_send_extinguish_request, - spawn_send_lock_assertion_broadcast_request, spawn_send_perform_lock_request, + get_relay_from_lock_assertion_receipt, get_relay_from_send_asset_status, + get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, + get_relay_from_transfer_proposal_receipt, get_relay_params, + get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, + spawn_send_ack_final_receipt_broadcast_request, spawn_send_assign_asset_request, + spawn_send_commit_prepare_request, spawn_send_create_asset_request, + spawn_send_extinguish_request, spawn_send_lock_assertion_broadcast_request, + spawn_send_lock_assertion_request, spawn_send_perform_lock_request, spawn_send_transfer_commence_request, spawn_send_transfer_proposal_receipt_request, }; use tokio::sync::RwLock; @@ -254,6 +256,57 @@ impl Satp for SatpService { } } + async fn send_asset_status( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Got a send asset status request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let send_asset_status_request = request.into_inner().clone(); + let request_id = send_asset_status_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &send_asset_status_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored SendAssetStatusRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing SendAssetStatusRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_send_asset_status_request(send_asset_status_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of send asset status request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Send asset status failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + async fn lock_assertion( &self, request: Request, @@ -775,6 +828,41 @@ pub fn process_ack_commence_request( } } +pub fn process_send_asset_status_request( + send_asset_status_request: SendAssetStatusRequest, + conf: config::Config, +) -> Result { + let request_id = send_asset_status_request.session_id.to_string(); + let is_valid_request = is_valid_send_asset_status_request(send_asset_status_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The send asset status request is valid\n"); + match send_lock_assertion_request(send_asset_status_request, conf) { + Ok(ack) => { + println!("Ack send asset status request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: send asset status request failed. {:?}", e), + }); + } + } + } else { + println!("The send asset status request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The send asset status request is invalid".to_string(), + }); + } +} + pub fn process_lock_assertion_request( lock_assertion_request: LockAssertionRequest, conf: config::Config, @@ -1071,6 +1159,33 @@ fn send_ack_commence_request( return Ok(reply); } +fn send_lock_assertion_request( + send_asset_status_request: SendAssetStatusRequest, + conf: config::Config, +) -> Result { + let request_id = &send_asset_status_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_send_asset_status(send_asset_status_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + let lock_assertion_request = create_lock_assertion_request(send_asset_status_request.clone()); + + spawn_send_lock_assertion_request( + lock_assertion_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Send Asset Status request".to_string(), + }; + return Ok(reply); +} + fn send_lock_assertion_receipt_request( lock_assertion_request: LockAssertionRequest, conf: config::Config, @@ -1103,25 +1218,12 @@ fn send_perform_lock_request( conf: config::Config, ) -> Result { let request_id = &ack_commence_request.session_id.to_string(); - let (relay_host, relay_port) = get_relay_from_ack_commence(ack_commence_request.clone()); - let (use_tls, tlsca_cert_path) = - get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let lock_assertion_request = create_lock_assertion_request(ack_commence_request.clone()); let driver_address = get_driver_address_from_ack_commence(ack_commence_request.clone()); let parsed_address = parse_address(driver_address)?; let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); match result { Ok(driver_info) => { - spawn_send_perform_lock_request( - driver_info, - ack_commence_request, - lock_assertion_request, - relay_host, - relay_port, - use_tls, - tlsca_cert_path, - conf, - ); + spawn_send_perform_lock_request(driver_info, ack_commence_request); let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), @@ -1142,33 +1244,6 @@ fn send_perform_lock_request( } } -fn send_lock_assertion_broadcast_request( - lock_assertion_request: LockAssertionRequest, - conf: config::Config, -) -> Result { - let request_id = &lock_assertion_request.session_id.to_string(); - let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); - let (use_tls, tlsca_cert_path) = - get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let lock_assertion_receipt_request = - create_lock_assertion_receipt_request(lock_assertion_request.clone()); - - spawn_send_lock_assertion_broadcast_request( - lock_assertion_receipt_request, - relay_host, - relay_port, - use_tls, - tlsca_cert_path, - conf, - ); - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request_id.to_string(), - message: "Ack of lock assert request".to_string(), - }; - return Ok(reply); -} - fn send_commit_prepare_request( lock_assertion_receipt_request: LockAssertionReceiptRequest, conf: config::Config, @@ -1378,3 +1453,8 @@ fn is_valid_transfer_completed_request( //TODO true } + +fn is_valid_send_asset_status_request(send_asset_status_request: SendAssetStatusRequest) -> bool { + //TODO + true +} From b8c17861d9722603d04e8131e147d8d4ba7409b9 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 15 Aug 2023 11:24:37 +0100 Subject: [PATCH 33/59] Implemented the status check functionality required for 2.1B, 3.2B, 3.4B, and 3.6B --- .../protos-rs/pkg/src/generated/relay.satp.rs | 2 + weaver/common/protos/relay/satp.proto | 1 + weaver/core/relay/driver/driver.rs | 1 + weaver/core/relay/src/services/satp_helper.rs | 137 +++++++-- .../core/relay/src/services/satp_service.rs | 283 +++++++++++------- 5 files changed, 289 insertions(+), 135 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index c1b94e14b9..b7147bd954 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -124,6 +124,8 @@ pub struct SendAssetStatusRequest { pub server_transfer_number: ::prost::alloc::string::String, #[prost(string, tag = "8")] pub server_signature: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub status: ::prost::alloc::string::String, } #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos/relay/satp.proto b/weaver/common/protos/relay/satp.proto index d7dd1b63c4..3d20759879 100644 --- a/weaver/common/protos/relay/satp.proto +++ b/weaver/common/protos/relay/satp.proto @@ -116,6 +116,7 @@ message SendAssetStatusRequest { string hash_prev_message = 6; string server_transfer_number = 7; string server_signature = 8; + string status = 9; } message LockAssertionRequest { diff --git a/weaver/core/relay/driver/driver.rs b/weaver/core/relay/driver/driver.rs index d3fa64f79b..661d8bd8ed 100644 --- a/weaver/core/relay/driver/driver.rs +++ b/weaver/core/relay/driver/driver.rs @@ -371,6 +371,7 @@ fn send_driver_mock_send_asset_status_helper(client: SatpClient, reques hash_prev_message: "hash_prev_message1".to_string(), server_transfer_number: "server_transfer_number1".to_string(), server_signature: "server_signature1".to_string(), + status: "status1".to_string(), }; println!("Sending send asset status request to remote gateway ..."); let response = client diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index fe1a56d25b..9894ca8f69 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -160,17 +160,17 @@ pub fn spawn_send_ack_commence_request( pub fn spawn_send_perform_lock_request( driver_info: Driver, - ack_commence_request: AckCommenceRequest, + perform_lock_request: PerformLockRequest, ) { tokio::spawn(async move { - let request_id = ack_commence_request.session_id.to_string(); + let request_id = perform_lock_request.session_id.to_string(); println!( "Locking the asset of the lock assertion request id: {:?}", request_id ); // TODO: pass the required info to lock the relevant asset // Call the driver to lock the asset - let result = call_perform_lock(driver_info, ack_commence_request).await; + let result = call_perform_lock(driver_info, perform_lock_request).await; match result { Ok(_) => { println!("Perform lock request sent to driver\n") @@ -184,7 +184,7 @@ pub fn spawn_send_perform_lock_request( } pub fn spawn_send_lock_assertion_broadcast_request( - lock_assertion_receipt_request: LockAssertionReceiptRequest, + lock_assertion_request: LockAssertionRequest, relay_host: String, relay_port: String, use_tls: bool, @@ -192,13 +192,16 @@ pub fn spawn_send_lock_assertion_broadcast_request( conf: Config, ) { tokio::spawn(async move { - let request_id = lock_assertion_receipt_request.session_id.to_string(); + let request_id = lock_assertion_request.session_id.to_string(); println!("Broadcasting the lock assertion request {:?}", request_id); // TODO // Broadcast the message to the network // Subscribe to the status event // Once the message is broadcast, call the call_lock_assertion_receipt endpoint // log the results + + let lock_assertion_receipt_request = + create_lock_assertion_receipt_request(lock_assertion_request.clone()); let result = call_lock_assertion_receipt( relay_host, relay_port, @@ -258,10 +261,6 @@ pub fn spawn_send_commit_prepare_request( // Spawning new thread to make the call_commit_prepare to receiver gateway tokio::spawn(async move { let request_id = commit_prepare_request.session_id.to_string(); - println!( - "Sending commit prepare request to receiver gateway: Request ID = {:?}", - request_id - ); let result = call_commit_prepare( relay_host, relay_port, @@ -278,7 +277,7 @@ pub fn spawn_send_commit_prepare_request( } pub fn spawn_send_create_asset_request( - commit_ready_request: CommitReadyRequest, + commit_prepare_request: CommitPrepareRequest, relay_host: String, relay_port: String, use_tls: bool, @@ -286,9 +285,9 @@ pub fn spawn_send_create_asset_request( conf: Config, ) { tokio::spawn(async move { - let request_id = commit_ready_request.session_id.to_string(); + let request_id = commit_prepare_request.session_id.to_string(); println!( - "Creating the asset corresponding to the commit ready request {:?}", + "Creating the asset corresponding to the commit prepare request {:?}", request_id ); // TODO @@ -296,6 +295,19 @@ pub fn spawn_send_create_asset_request( // Subscribe to the status event // Once the message is broadcast, call the call_commit_ready endpoint // log the results + }); +} + +pub fn spawn_send_commit_ready_request( + commit_ready_request: CommitReadyRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = commit_ready_request.session_id.to_string(); let result = call_commit_ready( relay_host, relay_port, @@ -313,7 +325,7 @@ pub fn spawn_send_create_asset_request( } pub fn spawn_send_assign_asset_request( - ack_final_receipt_request: AckFinalReceiptRequest, + commit_final_assertion_request: CommitFinalAssertionRequest, relay_host: String, relay_port: String, use_tls: bool, @@ -321,15 +333,28 @@ pub fn spawn_send_assign_asset_request( conf: Config, ) { tokio::spawn(async move { - let request_id = ack_final_receipt_request.session_id.to_string(); + let request_id = commit_final_assertion_request.session_id.to_string(); println!( - "Assigning the asset corresponding to the commit final assertion request {:?}", + "Assigning the asset corresponding to the commit final assertion request {:?}", request_id ); // TODO // Assigning the asset in the target network // Once the asset is assigned, call the call_ack_final_receipt endpoint // log the results + }); +} + +pub fn spawn_send_ack_final_receipt_request( + ack_final_receipt_request: AckFinalReceiptRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = ack_final_receipt_request.session_id.to_string(); let result = call_ack_final_receipt( relay_host, relay_port, @@ -347,7 +372,7 @@ pub fn spawn_send_assign_asset_request( } pub fn spawn_send_ack_final_receipt_broadcast_request( - transfer_completed_request: TransferCompletedRequest, + ack_final_receipt_request: AckFinalReceiptRequest, relay_host: String, relay_port: String, use_tls: bool, @@ -355,15 +380,18 @@ pub fn spawn_send_ack_final_receipt_broadcast_request( conf: Config, ) { tokio::spawn(async move { - let request_id = transfer_completed_request.session_id.to_string(); + let request_id = ack_final_receipt_request.session_id.to_string(); println!( - "Acknowledge final receipt broadcast of the transfer completed request {:?}", + "Acknowledge final receipt broadcast of the ack final receipt request {:?}", request_id ); // TODO // Ack final receipt broadcast // Once the broadcast is done, call the call_transfer_completed endpoint // log the results + + let transfer_completed_request = + create_transfer_completed_request(ack_final_receipt_request); let result = call_transfer_completed( relay_host, relay_port, @@ -381,7 +409,7 @@ pub fn spawn_send_ack_final_receipt_broadcast_request( } pub fn spawn_send_extinguish_request( - commit_final_assertion_request: CommitFinalAssertionRequest, + commit_ready_request: CommitReadyRequest, relay_host: String, relay_port: String, use_tls: bool, @@ -389,7 +417,7 @@ pub fn spawn_send_extinguish_request( conf: Config, ) { tokio::spawn(async move { - let request_id = commit_final_assertion_request.session_id.to_string(); + let request_id = commit_ready_request.session_id.to_string(); println!( "Extinguishing the asset corresponding to the commit final assertion request {:?}", request_id @@ -398,6 +426,23 @@ pub fn spawn_send_extinguish_request( // Assigning the asset in the target network // Once the asset is assigned, call the call_ack_final_receipt endpoint // log the results + }); +} + +pub fn spawn_send_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = commit_final_assertion_request.session_id.to_string(); + println!( + "Extinguishing the asset corresponding to the commit final assertion request {:?}", + request_id + ); let result = call_commit_final_assertion_receipt( relay_host, relay_port, @@ -416,11 +461,10 @@ pub fn spawn_send_extinguish_request( async fn call_perform_lock( driver_info: Driver, - ack_commence_request: AckCommenceRequest, + perform_lock_request: PerformLockRequest, ) -> Result<(), Error> { let client = get_driver_client(driver_info).await?; println!("Sending request to driver to lock the asset"); - let perform_lock_request = create_perform_lock_request(ack_commence_request); let ack = client .clone() .perform_lock(perform_lock_request) @@ -558,7 +602,7 @@ pub async fn call_lock_assertion_receipt( Ok(response) } -// Call the call_commit_ready endpoint on the sending gateway +// Call the call_commit_prepare endpoint on the sending gateway pub async fn call_commit_prepare( relay_host: String, relay_port: String, @@ -847,7 +891,7 @@ pub fn create_commit_prepare_request( } pub fn create_commit_ready_request( - commit_prepare_request: CommitPrepareRequest, + send_asset_status_request: SendAssetStatusRequest, ) -> CommitReadyRequest { // TODO: remove hard coded values let commit_ready_request = CommitReadyRequest { @@ -859,7 +903,7 @@ pub fn create_commit_ready_request( } pub fn create_commit_final_assertion_request( - commit_ready_request: CommitReadyRequest, + send_asset_status_request: SendAssetStatusRequest, ) -> CommitFinalAssertionRequest { // TODO: remove hard coded values let commit_final_assertion_request = CommitFinalAssertionRequest { @@ -871,7 +915,7 @@ pub fn create_commit_final_assertion_request( } pub fn create_ack_final_receipt_request( - commit_final_assertion_request: CommitFinalAssertionRequest, + send_asset_status_request: SendAssetStatusRequest, ) -> AckFinalReceiptRequest { // TODO: remove hard coded values let ack_final_receipt_request = AckFinalReceiptRequest { @@ -902,6 +946,45 @@ pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> return perform_lock_request; } +pub fn generate_commit_final_assertion_request( + commit_ready_request: CommitReadyRequest, +) -> CommitFinalAssertionRequest { + // TODO Get the corresponding send_asset_status_request from db + // TODO: remove hard coded values + let commit_final_assertion_request = CommitFinalAssertionRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_final_assertion_request; +} + +pub fn generate_commit_ready_request( + commit_prepare_request: CommitPrepareRequest, +) -> CommitReadyRequest { + // TODO Get the corresponding send_asset_status_request from db + // TODO: remove hard coded values + let commit_ready_request = CommitReadyRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_ready_request; +} + +pub fn generate_ack_final_receipt_request( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> AckFinalReceiptRequest { + // TODO Get the corresponding send_asset_status_request from db + // TODO: remove hard coded values + let ack_final_receipt_request = AckFinalReceiptRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return ack_final_receipt_request; +} + pub fn get_satp_requests_local_db(conf: Config) -> Database { let db = Database { db_path: format!( @@ -1083,7 +1166,7 @@ pub fn get_relay_from_send_asset_status( return ("localhost".to_string(), "9085".to_string()); } -pub fn get_driver_address_from_ack_commence(ack_commence_request: AckCommenceRequest) -> String { +pub fn get_driver_address_from_perform_lock(perform_lock_request: PerformLockRequest) -> String { // TODO return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); } diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 0d95acab03..b9bf229eb9 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,5 +1,6 @@ // Internal generated modules use weaverpb::common::ack::{ack, Ack}; +use weaverpb::driver::driver::PerformLockRequest; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{ AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, @@ -12,8 +13,9 @@ use weaverpb::relay::satp::{ use crate::error::Error; use crate::relay_proto::parse_address; use crate::services::satp_helper::{ - create_ack_error_message, get_request_id_from_transfer_proposal_receipt, - log_request_in_local_satp_db, log_request_in_remote_satp_db, + create_ack_error_message, create_perform_lock_request, + get_request_id_from_transfer_proposal_receipt, log_request_in_local_satp_db, + log_request_in_remote_satp_db, }; use super::helpers::get_driver; @@ -21,21 +23,20 @@ use super::helpers::get_driver; use super::satp_helper::{ create_ack_commence_request, create_ack_final_receipt_request, create_commit_final_assertion_request, create_commit_prepare_request, - create_commit_ready_request, create_lock_assertion_receipt_request, - create_lock_assertion_request, create_transfer_commence_request, + create_commit_ready_request, create_lock_assertion_request, create_transfer_commence_request, create_transfer_completed_request, create_transfer_proposal_receipt_request, - get_driver_address_from_ack_commence, get_relay_from_ack_commence, + get_driver_address_from_perform_lock, get_relay_from_ack_commence, get_relay_from_ack_final_receipt, get_relay_from_commit_final_assertion, get_relay_from_commit_prepare, get_relay_from_commit_ready, get_relay_from_lock_assertion, - get_relay_from_lock_assertion_receipt, get_relay_from_send_asset_status, - get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, - get_relay_from_transfer_proposal_receipt, get_relay_params, + get_relay_from_transfer_commence, get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, - spawn_send_ack_final_receipt_broadcast_request, spawn_send_assign_asset_request, - spawn_send_commit_prepare_request, spawn_send_create_asset_request, - spawn_send_extinguish_request, spawn_send_lock_assertion_broadcast_request, - spawn_send_lock_assertion_request, spawn_send_perform_lock_request, - spawn_send_transfer_commence_request, spawn_send_transfer_proposal_receipt_request, + spawn_send_ack_final_receipt_broadcast_request, spawn_send_ack_final_receipt_request, + spawn_send_assign_asset_request, spawn_send_commit_final_assertion_request, + spawn_send_commit_prepare_request, spawn_send_commit_ready_request, + spawn_send_create_asset_request, spawn_send_extinguish_request, + spawn_send_lock_assertion_broadcast_request, spawn_send_lock_assertion_request, + spawn_send_perform_lock_request, spawn_send_transfer_commence_request, + spawn_send_transfer_proposal_receipt_request, }; use tokio::sync::RwLock; use tonic::{Request, Response, Status}; @@ -657,7 +658,9 @@ pub fn process_transfer_proposal_claims_request( if is_valid_request { println!("The transfer proposal claims request is valid\n"); - match send_transfer_proposal_receipt_request(transfer_proposal_claims_request, conf) { + let transfer_proposal_receipt_request = + create_transfer_proposal_receipt_request(transfer_proposal_claims_request.clone()); + match send_transfer_proposal_receipt_request(transfer_proposal_receipt_request, conf) { Ok(ack) => { println!("Ack transfer proposal claims request."); let reply = Ok(ack); @@ -693,7 +696,9 @@ pub fn process_transfer_proposal_receipt_request( if is_valid_request { println!("The transfer proposal receipt request is valid\n"); - match send_transfer_commence_request(transfer_proposal_receipt_request, conf) { + let transfer_commence_request = + create_transfer_commence_request(transfer_proposal_receipt_request.clone()); + match send_transfer_commence_request(transfer_commence_request, conf) { Ok(ack) => { println!("Ack transfer proposal receipt request."); let reply = Ok(ack); @@ -729,7 +734,8 @@ pub fn process_transfer_commence_request( if is_valid_request { println!("The transfer commence request is valid\n"); - match send_ack_commence_request(transfer_commence_request, conf) { + let ack_commence_request = create_ack_commence_request(transfer_commence_request.clone()); + match send_ack_commence_request(ack_commence_request, conf) { Ok(ack) => { println!("Ack transfer commence request."); let reply = Ok(ack); @@ -754,43 +760,6 @@ pub fn process_transfer_commence_request( } } -pub fn process_tranfer_proposal_receipt_request( - transfer_proposal_receipt_request: TransferProposalReceiptRequest, - conf: config::Config, -) -> Result { - let request_id = - get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); - let is_valid_request = - is_valid_transfer_proposal_receipt_request(transfer_proposal_receipt_request.clone()); - - // TODO some processing - if is_valid_request { - println!("The transfer proposal receipt request is valid\n"); - match send_transfer_commence_request(transfer_proposal_receipt_request, conf) { - Ok(ack) => { - println!("Ack transfer proposal receipt request."); - let reply = Ok(ack); - println!("Sending back Ack: {:?}\n", reply); - reply - } - Err(e) => { - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error: Ack transfer proposal receipt failed. {:?}", e), - }); - } - } - } else { - println!("The transfer proposal receipt request is invalid\n"); - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: "Error: The transfer proposal receipt request is invalid".to_string(), - }); - } -} - /// process_ack_commence_request is invoked by the receiver gateway to ack the transfer commence request /// requested ed by the sender gateway pub fn process_ack_commence_request( @@ -803,7 +772,8 @@ pub fn process_ack_commence_request( // TODO some processing if is_valid_request { println!("The ack commence request is valid\n"); - match send_perform_lock_request(ack_commence_request, conf) { + let perform_lock_request = create_perform_lock_request(ack_commence_request); + match send_perform_lock_request(perform_lock_request, conf) { Ok(ack) => { println!("Ack ack commence request."); let reply = Ok(ack); @@ -838,9 +808,40 @@ pub fn process_send_asset_status_request( // TODO some processing if is_valid_request { println!("The send asset status request is valid\n"); - match send_lock_assertion_request(send_asset_status_request, conf) { + + let result; + let status = send_asset_status_request.status.as_str(); + match status { + "Locked" => { + println!("Received asset status as Locked. Sending the lock assertion request"); + let lock_assertion_request = + create_lock_assertion_request(send_asset_status_request); + result = send_lock_assertion_request(lock_assertion_request, conf) + } + "Created" => { + println!("Received asset status as Created. Sending the commit ready request"); + let commit_ready_request = create_commit_ready_request(send_asset_status_request); + result = send_commit_ready_request(commit_ready_request, conf); + } + "Extinguished" => { + println!("Received asset status as Extinguished. Sending the commit final assertion request"); + let commit_final_assertion_request = + create_commit_final_assertion_request(send_asset_status_request); + result = send_commit_final_assertion_request(commit_final_assertion_request, conf) + } + "Finalized" => { + println!( + "Received asset status as Finalized. Sending the ack final receipt request" + ); + let ack_final_receipt_request = + create_ack_final_receipt_request(send_asset_status_request.clone()); + result = send_ack_final_receipt_request(ack_final_receipt_request, conf) + } + _ => result = Err(Error::Simple(format!("Invalid asset status: {}", status))), + } + + match result { Ok(ack) => { - println!("Ack send asset status request."); let reply = Ok(ack); println!("Sending back Ack: {:?}\n", reply); reply @@ -849,7 +850,7 @@ pub fn process_send_asset_status_request( return Ok(Ack { status: ack::Status::Error as i32, request_id: request_id.to_string(), - message: format!("Error: send asset status request failed. {:?}", e), + message: format!("Error: sending request failed. {:?}", e), }); } } @@ -872,7 +873,7 @@ pub fn process_lock_assertion_request( if is_valid_request { println!("The lock assertion request is valid\n"); - match send_lock_assertion_receipt_request(lock_assertion_request, conf) { + match send_lock_assertion_broadcast_request(lock_assertion_request, conf) { Ok(ack) => { println!("Ack lock assertion request."); let reply = Ok(ack); @@ -908,7 +909,9 @@ pub fn process_lock_assertion_receipt_request( // TODO some processing if is_valid_request { println!("The lock assertion receipt request is valid\n"); - match send_commit_prepare_request(lock_assertion_receipt_request, conf) { + let commit_prepare_request = + create_commit_prepare_request(lock_assertion_receipt_request.clone()); + match send_commit_prepare_request(commit_prepare_request, conf) { Ok(ack) => { println!("Ack lock assertion receipt request."); let reply = Ok(ack); @@ -943,7 +946,7 @@ pub fn process_commit_prepare_request( // TODO some processing if is_valid_request { println!("The commit prepare request is valid\n"); - match send_commit_ready_request(commit_prepare_request, conf) { + match send_create_asset_request(commit_prepare_request, conf) { Ok(ack) => { println!("Ack commit prepare request."); let reply = Ok(ack); @@ -978,7 +981,7 @@ pub fn process_commit_ready_request( // TODO some processing if is_valid_request { println!("The commit ready request is valid\n"); - match send_commit_final_assertion_request(commit_ready_request, conf) { + match send_extinguish_request(commit_ready_request, conf) { Ok(ack) => { println!("Ack commit ready request."); let reply = Ok(ack); @@ -1014,7 +1017,7 @@ pub fn process_commit_final_assertion_request( // TODO some processing if is_valid_request { println!("The commit final assertion request is valid\n"); - match send_ack_final_receipt_request(commit_final_assertion_request, conf) { + match send_assign_asset_request(commit_final_assertion_request, conf) { Ok(ack) => { println!("Ack commit final assertion request."); let reply = Ok(ack); @@ -1049,7 +1052,7 @@ pub fn process_ack_final_receipt_request( // TODO some processing if is_valid_request { println!("The ack final receipt request is valid\n"); - match send_transfer_completed_request(ack_final_receipt_request, conf) { + match send_ack_final_receipt_broadcast_request(ack_final_receipt_request, conf) { Ok(ack) => { println!("Ack ack final receipt request."); let reply = Ok(ack); @@ -1075,17 +1078,15 @@ pub fn process_ack_final_receipt_request( } fn send_transfer_proposal_receipt_request( - transfer_proposal_claims_request: TransferProposalClaimsRequest, + transfer_proposal_receipt_request: TransferProposalReceiptRequest, conf: config::Config, ) -> Result { let request_id = - get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); + get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); let (relay_host, relay_port) = - get_relay_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); + get_relay_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let transfer_proposal_receipt_request = - create_transfer_proposal_receipt_request(transfer_proposal_claims_request.clone()); spawn_send_transfer_proposal_receipt_request( transfer_proposal_receipt_request, @@ -1104,17 +1105,14 @@ fn send_transfer_proposal_receipt_request( } fn send_transfer_commence_request( - transfer_proposal_receipt_request: TransferProposalReceiptRequest, + transfer_commence_request: TransferCommenceRequest, conf: config::Config, ) -> Result { - let request_id = - get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); + let request_id = transfer_commence_request.session_id.clone(); let (relay_host, relay_port) = - get_relay_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); + get_relay_from_transfer_commence(transfer_commence_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let transfer_commence_request = - create_transfer_commence_request(transfer_proposal_receipt_request.clone()); spawn_send_transfer_commence_request( transfer_commence_request, @@ -1133,15 +1131,13 @@ fn send_transfer_commence_request( } fn send_ack_commence_request( - transfer_commence_request: TransferCommenceRequest, + ack_commence_request: AckCommenceRequest, conf: config::Config, ) -> Result { - let request_id = &transfer_commence_request.session_id.to_string(); - let (relay_host, relay_port) = - get_relay_from_transfer_commence(transfer_commence_request.clone()); + let request_id = &ack_commence_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_ack_commence(ack_commence_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let ack_commence_request = create_ack_commence_request(transfer_commence_request.clone()); spawn_send_ack_commence_request( ack_commence_request, @@ -1160,15 +1156,13 @@ fn send_ack_commence_request( } fn send_lock_assertion_request( - send_asset_status_request: SendAssetStatusRequest, + lock_assertion_request: LockAssertionRequest, conf: config::Config, ) -> Result { - let request_id = &send_asset_status_request.session_id.to_string(); - let (relay_host, relay_port) = - get_relay_from_send_asset_status(send_asset_status_request.clone()); + let request_id = &lock_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let lock_assertion_request = create_lock_assertion_request(send_asset_status_request.clone()); spawn_send_lock_assertion_request( lock_assertion_request, @@ -1186,7 +1180,7 @@ fn send_lock_assertion_request( return Ok(reply); } -fn send_lock_assertion_receipt_request( +fn send_lock_assertion_broadcast_request( lock_assertion_request: LockAssertionRequest, conf: config::Config, ) -> Result { @@ -1194,11 +1188,9 @@ fn send_lock_assertion_receipt_request( let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let lock_assertion_receipt_request = - create_lock_assertion_receipt_request(lock_assertion_request.clone()); spawn_send_lock_assertion_broadcast_request( - lock_assertion_receipt_request, + lock_assertion_request, relay_host, relay_port, use_tls, @@ -1214,16 +1206,16 @@ fn send_lock_assertion_receipt_request( } fn send_perform_lock_request( - ack_commence_request: AckCommenceRequest, + perform_lock_request: PerformLockRequest, conf: config::Config, ) -> Result { - let request_id = &ack_commence_request.session_id.to_string(); - let driver_address = get_driver_address_from_ack_commence(ack_commence_request.clone()); + let request_id = &perform_lock_request.session_id.to_string(); + let driver_address = get_driver_address_from_perform_lock(perform_lock_request.clone()); let parsed_address = parse_address(driver_address)?; let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); match result { Ok(driver_info) => { - spawn_send_perform_lock_request(driver_info, ack_commence_request); + spawn_send_perform_lock_request(driver_info, perform_lock_request); let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), @@ -1245,16 +1237,13 @@ fn send_perform_lock_request( } fn send_commit_prepare_request( - lock_assertion_receipt_request: LockAssertionReceiptRequest, + commit_prepare_request: CommitPrepareRequest, conf: config::Config, ) -> Result { - let request_id = &lock_assertion_receipt_request.session_id.to_string(); - let (relay_host, relay_port) = - get_relay_from_lock_assertion_receipt(lock_assertion_receipt_request.clone()); + let request_id = &commit_prepare_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let commit_prepare_request = - create_commit_prepare_request(lock_assertion_receipt_request.clone()); spawn_send_commit_prepare_request( commit_prepare_request, @@ -1273,6 +1262,33 @@ fn send_commit_prepare_request( } fn send_commit_ready_request( + commit_ready_request: CommitReadyRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_ready_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_commit_ready(commit_ready_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_commit_ready_request( + commit_ready_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_create_asset_request( commit_prepare_request: CommitPrepareRequest, conf: config::Config, ) -> Result { @@ -1281,10 +1297,9 @@ fn send_commit_ready_request( let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let commit_ready_request = create_commit_ready_request(commit_prepare_request.clone()); spawn_send_create_asset_request( - commit_ready_request, + commit_prepare_request, relay_host, relay_port, use_tls, @@ -1300,7 +1315,7 @@ fn send_commit_ready_request( return Ok(reply); } -fn send_commit_final_assertion_request( +fn send_extinguish_request( commit_ready_request: CommitReadyRequest, conf: config::Config, ) -> Result { @@ -1309,10 +1324,36 @@ fn send_commit_final_assertion_request( let (relay_host, relay_port) = get_relay_from_commit_ready(commit_ready_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let commit_final_assertion_request = - create_commit_final_assertion_request(commit_ready_request.clone()); spawn_send_extinguish_request( + commit_ready_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_final_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_commit_final_assertion(commit_final_assertion_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_commit_final_assertion_request( commit_final_assertion_request, relay_host, relay_port, @@ -1330,6 +1371,34 @@ fn send_commit_final_assertion_request( } fn send_ack_final_receipt_request( + ack_final_receipt_request: AckFinalReceiptRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &ack_final_receipt_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_ack_final_receipt_request( + ack_final_receipt_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_assign_asset_request( commit_final_assertion_request: CommitFinalAssertionRequest, conf: config::Config, ) -> Result { @@ -1339,11 +1408,9 @@ fn send_ack_final_receipt_request( get_relay_from_commit_final_assertion(commit_final_assertion_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let ack_final_receipt_request = - create_ack_final_receipt_request(commit_final_assertion_request.clone()); spawn_send_assign_asset_request( - ack_final_receipt_request, + commit_final_assertion_request, relay_host, relay_port, use_tls, @@ -1359,7 +1426,7 @@ fn send_ack_final_receipt_request( return Ok(reply); } -fn send_transfer_completed_request( +fn send_ack_final_receipt_broadcast_request( ack_final_receipt_request: AckFinalReceiptRequest, conf: config::Config, ) -> Result { @@ -1373,7 +1440,7 @@ fn send_transfer_completed_request( create_transfer_completed_request(ack_final_receipt_request.clone()); spawn_send_ack_final_receipt_broadcast_request( - transfer_completed_request, + ack_final_receipt_request, relay_host, relay_port, use_tls, From 5791f2f25d585340b7614808f925e029ca8ee86f Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 21 Aug 2023 14:38:34 +0100 Subject: [PATCH 34/59] First iteration of switching to real driver (fabric) --- .../server/helpers/fabric-functions.ts | 714 ++++++++++++++++ .../fabric-driver/server/helpers/helpers.ts | 764 ++++++++++++++++++ .../interop-setup/configure-network.ts | 230 ++++++ .../fabric-driver/server/helpers/logger.ts | 29 + .../core/drivers/fabric-driver/server/satp.ts | 196 +++++ .../drivers/fabric-driver/server/server.ts | 22 + weaver/core/relay/config/Dummy_Relay.toml | 2 +- 7 files changed, 1956 insertions(+), 1 deletion(-) create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/helpers.ts create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/logger.ts create mode 100644 weaver/core/drivers/fabric-driver/server/satp.ts diff --git a/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts b/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts new file mode 100644 index 0000000000..08b7597980 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts @@ -0,0 +1,714 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Gateway, Wallets, Contract, X509Identity } from 'fabric-network' +import { getNetworkConfig, saveUserCertToFile, handlePromise } from './helpers' +import FabricCAServices from 'fabric-ca-client' +import { Certificate } from '@fidm/x509' +import { Utils, ICryptoKey } from 'fabric-common' +import * as membership_pb from "@hyperledger/cacti-weaver-protos-js/common/membership_pb" +import * as iin_agent_pb from "@hyperledger/cacti-weaver-protos-js/identity/agent_pb" +import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric' +import * as path from 'path' +import * as dotenv from 'dotenv' +dotenv.config({ path: path.resolve(__dirname, '../../.env') }) +import * as fs from 'fs' + +export type InvocationSpec = { + contractName: string + channel: string + args: string[] + ccFunc: string +} + +const getUserCertBase64 = async ( + networkName: string, + username: string +) => { + const wallet = await getWalletForNetwork(networkName) + const userId = await wallet.get(username) + if (!userId) { + throw new Error(`User ${username} not present in wallet of ${networkName}.`) + } + return Buffer.from((userId as X509Identity).credentials.certificate).toString('base64') +} + +const walletSetup = async ( + networkName: string, + ccp: any, + mspId: string, + userName: string, + userPwd: string = '', + isNetworkAdmin: boolean = false, + isIINAgent: boolean = false, + register: boolean = false, + logger: any = console +) => { + // Create a new CA client for interacting with the CA. + const org = ccp.client['organization'] + const caName = ccp.organizations[org]['certificateAuthorities'][0] + const caURL = ccp.certificateAuthorities[caName].url + const ca = new FabricCAServices(caURL) + const ident = ca.newIdentityService() + + const wallet = await getWalletForNetwork(networkName) + + // build a user object for authenticating with the CA + // Check to see if we've already enrolled the admin user. + let adminIdentity = await wallet.get('admin') + + if (adminIdentity) { + logger.debug( + 'An identity for the admin user "admin" already exists in the wallet.' + ) + } else { + // Enroll the admin user, and import the new identity into the wallet. + const enrollment = await ca.enroll({ + enrollmentID: 'admin', + enrollmentSecret: 'adminpw' + }) + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes() + }, + mspId: mspId, + type: 'X.509' + } + await wallet.put('admin', x509Identity) + adminIdentity = await wallet.get('admin') + } + const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type) + const adminUser = await provider.getUserContext(adminIdentity, 'admin') + const identity = await wallet.get(userName) + logger.debug(`user ${userName}`) + if (!identity) { + // Register the user, enroll the user, and import the new identity into the wallet. + if (!register) { + logger.error(`Identity ${userName} does not exist. Please add user in the network.\n`) + return + } + var secret, enrollment + var enrollmentDone = false + var attributes = [] + if (isNetworkAdmin) { + attributes.push({ "name": "network-admin", "value": "true", "ecert": true }) + } + if (isIINAgent) { + attributes.push({ "name": "iin-agent", "value": "true", "ecert": true }) + } + try { + if (!userPwd) { + secret = await ca.register( + { + affiliation: 'org1.department1', + enrollmentID: userName, + maxEnrollments: -1, + role: 'client', + attrs: attributes + }, + adminUser + ) + } + else { + secret = await ca.register( + { + affiliation: 'org1.department1', + enrollmentID: userName, + enrollmentSecret: userPwd, + maxEnrollments: -1, + role: 'client', + attrs: attributes + }, + adminUser + ) + } + logger.info(`Wallet Setup: Sucessful ${secret}`) + } catch(error) { + const registeredUser = `Identity '${userName}' is already ` + if (!userPwd || !(error.message.includes("Identity ") && error.message.includes(userName) && error.message.includes(" is already registered"))) { + throw new Error(`user ${userName} registration with Fabric CA failed with error: ${error}`) + } else { + try { + enrollment = await ca.enroll({ + enrollmentID: userName, + enrollmentSecret: userPwd + }) + enrollmentDone = true + } catch (error) { + throw new Error(`user ${userName} registration/enrollment with Fabric CA failed with error: ${error}`) + } + } + } + + if (!enrollmentDone) { + enrollment = await ca.enroll({ + enrollmentID: userName, + enrollmentSecret: secret + }) + } + + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes() + }, + mspId: mspId, + type: 'X.509' + } + await wallet.put(userName, x509Identity) + } + else { + logger.debug(`Identity ${userName} already exists.\n`) + } + + return wallet +} + +const enrollAndRecordWalletIdentity = async ( + userName: string, + userPwd: string, + networkName: string, + isNetworkAdmin: boolean = false, + isIINAgent: boolean = false, + logger: any = console +) => { + const net = getNetworkConfig(networkName) + const ccpPath = path.resolve(__dirname, net.connProfilePath) + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) + logger.info(net) + + const wallet = await walletSetup(networkName, ccp, net.mspId, userName, userPwd, isNetworkAdmin, isIINAgent, true) + saveUserCertToFile(userName, networkName) + + return wallet +} + +const getCurrentNetworkCredentialPath = (networkName: string): string => { + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, networkName) + : path.join(__dirname, '../data', 'credentials', networkName) + return credentialsPath +} + +const getCredentialPath = (): string => { + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER) + : path.join(__dirname, '../data', 'credentials') + return credentialsPath +} + +const generateAccessControl = async ( + channel: string, + contractName: string, + connProfilePath: string, + networkName: string, + templatePath: string, + username: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console +): Promise => { + const { wallet } = await fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + logger, + mspId + }) + const templateJSON = JSON.parse( + Buffer.from(fs.readFileSync(templatePath)).toString() + ) + const [keyCert, keyCertError] = await handlePromise( + getKeyAndCertForRemoteRequestbyUserName(wallet, username) + ) + if (keyCertError) { + logger.error( + 'Error fetching key and certificate from network', + keyCertError + ) + } + const updatedRules = templateJSON.rules.map(rule => { + if (rule.principalType == 'ca') { + rule.principal = mspId + } else if (rule.principalType == 'certificate') { + rule.principal = keyCert.cert + } else { + logger.error( + 'Error Invalid Principal Type in template file' + ) + } + return rule + }) + const accessControlJSON = { + ...templateJSON, + securityDomain: networkName, + rules: updatedRules + } + logger.debug(`AccessControlJSON ${JSON.stringify(accessControlJSON)}`) + const credentialsPath = getCurrentNetworkCredentialPath(networkName) + fs.writeFileSync( + path.join(credentialsPath, `access-control.json`), + JSON.stringify(accessControlJSON) + ) +} + +const generateVerificationPolicy = async ( + channel, + contractName, + connProfilePath, + networkName: string, + templatePath: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console +): Promise => { + const templateJSON = JSON.parse( + Buffer.from(fs.readFileSync(templatePath)).toString() + ) + const { gateway } = await fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + mspId, + logger + }) + + const network = await gateway.getNetwork(channel) + const mspConfig = await getMspConfig(network, logger) + const criteria = Object.keys(formatMSP(mspConfig, networkName).members) + const newIdentifiers = templateJSON.identifiers.map(identifier => { + identifier.policy.criteria = criteria + return identifier + }) + const verificationPolicy = { + ...templateJSON, + identifiers: newIdentifiers, + securityDomain: networkName + } + logger.debug(`VerificationPolicyJSON ${JSON.stringify(verificationPolicy)}`) + const credentialsPath = getCurrentNetworkCredentialPath(networkName) + logger.debug('Credential Path', credentialsPath) + fs.writeFileSync( + path.join(credentialsPath, `verification-policy.json`), + JSON.stringify(verificationPolicy) + ) +} + +const generateMembership = async ( + channel: string, + contractName: string, + connProfilePath: string, + networkName: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console, + iinAgent: boolean = false +): Promise => { + const { gateway } = await fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + mspId, + logger + }) + + const network = await gateway.getNetwork(channel) + const mspConfig = await getMspConfig(network, logger) + const membershipJSON = formatMSP(mspConfig, networkName) + const membershipJSONStr = JSON.stringify(membershipJSON) + logger.debug(`membershipJSON: ${membershipJSONStr}`) + + const credentialsPath = getCurrentNetworkCredentialPath(networkName) + logger.debug(`Credentials Path: ${credentialsPath}`) + if (!fs.existsSync(credentialsPath)) { + logger.debug(`Creating directory`) + fs.mkdirSync(credentialsPath, { recursive: true }) + } + + fs.writeFileSync( + path.join(credentialsPath, `membership.json`), + membershipJSONStr + ) + + if (iinAgent) { + // Generate protobufs and attestations for all other networks that have IIN Agents + const credentialFolderPath = getCredentialPath() + const otherNetworkNames = fs + .readdirSync(credentialFolderPath, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .filter(item => item.name.startsWith('network')) // HACK until we add IIN Agents for Corda networks + .map(item => item.name) + // Reorder the array so that the local network is the first element + // We need to record local membership before recording other networks' memberships + otherNetworkNames.splice(otherNetworkNames.indexOf(networkName), 1) + + if (otherNetworkNames.length > 0) { + // Convert membership object to protobuf + let membershipProto = new membership_pb.Membership() + membershipProto.setSecuritydomain(membershipJSON.securityDomain) + Object.keys(membershipJSON.members).forEach( (memberName, index) => { + const certInfo = membershipJSON.members[memberName] + let memberProto = new membership_pb.Member() + memberProto.setType(certInfo.type) + memberProto.setValue(certInfo.value) + membershipProto.getMembersMap().set(memberName, memberProto) + }) + + // For every other network, generate a counter attested membership set + const serializedMembership = membershipProto.serializeBinary() + const serializedMembershipBase64 = Buffer.from(serializedMembership).toString('base64') + const nonce = 'j849j94j40f440fkfjkld0e043' // Some random string + const membershipBase64WithNonce = serializedMembershipBase64 + nonce + // Get wallet key and cert for this network's IIN Agent + const localWallet = await getWalletForNetwork(networkName) + const localKeyCert = await getKeyAndCertForRemoteRequestbyUserName(localWallet, 'iinagent') + // Sign using wallet identity + let securityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() + securityDomainMember.setSecurityDomain(membershipJSON.securityDomain) + securityDomainMember.setMemberId(Object.keys(membershipJSON.members)[0]) + let localAttestation = new iin_agent_pb.Attestation() + localAttestation.setUnitIdentity(securityDomainMember) + localAttestation.setCertificate(localKeyCert.cert) + const localSig = InteroperableHelper.signMessage(membershipBase64WithNonce, localKeyCert.key.toBytes()) + localAttestation.setSignature(localSig) + localAttestation.setNonce(nonce) + let attestedMembershipSet = new iin_agent_pb.CounterAttestedMembership.AttestedMembershipSet() + attestedMembershipSet.setMembership(serializedMembershipBase64) + attestedMembershipSet.setAttestationsList( [ localAttestation ] ) + const serializedAttestedMembershipSet = attestedMembershipSet.serializeBinary() + const serializedttestedMembershipSetBase64 = Buffer.from(serializedAttestedMembershipSet).toString('base64') + const serializedttestedMembershipSetBase64WithNonce = serializedttestedMembershipSetBase64 + nonce + for (const otherNetworkName of otherNetworkNames) { + // Get wallet key and cert for other network's IIN Agent + const otherWallet = await getWalletForNetwork(otherNetworkName) + const otherKeyCert = await getKeyAndCertForRemoteRequestbyUserName(otherWallet, 'iinagent') + // Sign using wallet identity + let otherSecurityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() + otherSecurityDomainMember.setSecurityDomain(otherNetworkName) + otherSecurityDomainMember.setMemberId(getNetworkConfig(otherNetworkName).mspId) + let otherAttestation = new iin_agent_pb.Attestation() + otherAttestation.setUnitIdentity(otherSecurityDomainMember) + otherAttestation.setCertificate(otherKeyCert.cert) + const otherSig = InteroperableHelper.signMessage(serializedttestedMembershipSetBase64WithNonce, otherKeyCert.key.toBytes()) + otherAttestation.setSignature(otherSig) + otherAttestation.setNonce(nonce) + + // Generate chaincode argument and save it in a file + let counterAttestedMembership = new iin_agent_pb.CounterAttestedMembership() + counterAttestedMembership.setAttestedMembershipSet(serializedttestedMembershipSetBase64) + counterAttestedMembership.setAttestationsList( [ otherAttestation ] ) + + fs.writeFileSync( + path.join(credentialsPath, `attested-membership-${otherNetworkName}.proto.serialized`), + Buffer.from(counterAttestedMembership.serializeBinary()).toString('base64') + ) + } + } + } + return membershipJSON +} + +const formatMSP = (mspConfig: MspConfig, networkId: string) => { + const memberObject = { members: {}, securityDomain: networkId } + Object.entries(mspConfig).forEach(([name, value], _) => { + // const cert = Certificate.fromPEM(Buffer.from(value.root_certs[0], 'base64')) + memberObject.members[name] = { + type: 'ca', + value: Buffer.from(value.root_certs[0], 'base64').toString('utf8') + } + }) + return memberObject +} + +type MspConfig = { + [key: string]: { admins: any; root_certs: any; name: string } +} + +const getMspConfig = async ( + network, + logger: any = console +): Promise => { + const mspConfigs = network.channel.getMspids() + const orgMspConfig = {} + logger.debug(mspConfigs) + logger.debug(network.channel.getMsp(mspConfigs[0])) + + mspConfigs.forEach(mspId => { + if (mspId !== 'OrdererMSP') { + logger.info('Getting MSP Info for org with MSP ID: ' + mspId + '.') + const mspConfig = network.getChannel().getMsp(mspId) + delete mspConfig.id + if (Array.isArray(mspConfig.admins)) { + for (let i = 0; i < mspConfig.admins.length; i++) { + mspConfig.admins[i] = Buffer.from(mspConfig.admins[i]).toString( + 'base64' + ) + } + } else if (mspConfig.admins.length === 0) { + mspConfig.admins = [] + } else { + mspConfig.admins = [Buffer.from(mspConfig.admins).toString('base64')] + } + if (Array.isArray(mspConfig.rootCerts)) { + for (let i = 0; i < mspConfig.rootCerts.length; i++) { + mspConfig.rootCerts[i] = Buffer.from(mspConfig.rootCerts[i]).toString( + 'base64' + ) + } + } else if (mspConfig.rootCerts.length === 0) { + mspConfig.rootCerts = [] + } else { + mspConfig.rootCerts = [ + Buffer.from(mspConfig.rootCerts).toString('base64') + ] + } + mspConfig.root_certs = mspConfig.rootCerts + delete mspConfig.rootCerts + if (Array.isArray(mspConfig.intermediateCerts)) { + for (let i = 0; i < mspConfig.intermediateCerts.length; i++) { + mspConfig.intermediateCerts[i] = Buffer.from( + mspConfig.intermediateCerts[i] + ).toString('base64') + } + } else if (mspConfig.intermediateCerts.length === 0) { + mspConfig.intermediateCerts = [] + } else { + mspConfig.intermediateCerts = [ + Buffer.from(mspConfig.intermediateCerts).toString('base64') + ] + } + mspConfig.intermediate_certs = mspConfig.intermediateCerts + delete mspConfig.intermediateCerts + if (Array.isArray(mspConfig.tlsRootCerts)) { + for (let i = 0; i < mspConfig.tlsRootCerts.length; i++) { + mspConfig.tlsRootCerts[i] = Buffer.from( + mspConfig.tlsRootCerts[i] + ).toString('base64') + } + } else if (mspConfig.tlsRootCerts.length === 0) { + mspConfig.tlsRootCerts = [] + } else { + mspConfig.tlsRootCerts = [ + Buffer.from(mspConfig.tlsRootCerts).toString('base64') + ] + } + mspConfig.tls_root_certs = mspConfig.tlsRootCerts + delete mspConfig.tlsRootCerts + if (Array.isArray(mspConfig.tlsIntermediateCerts)) { + for (let i = 0; i < mspConfig.tlsIntermediateCerts.length; i++) { + mspConfig.tlsIntermediateCerts[i] = Buffer.from( + mspConfig.tlsIntermediateCerts[i] + ).toString('base64') + } + } else if (mspConfig.tlsIntermediateCerts.length === 0) { + mspConfig.tlsIntermediateCerts = [] + } else { + mspConfig.tlsIntermediateCerts = [ + Buffer.from(mspConfig.tlsIntermediateCerts).toString('base64') + ] + } + mspConfig.tls_intermediate_certs = mspConfig.tlsIntermediateCerts + delete mspConfig.tlsIntermediateCerts + orgMspConfig[mspId] = mspConfig + } + }) + return orgMspConfig +} + +async function fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + mspId = global.__DEFAULT_MSPID__, + logger = console, + discoveryEnabled = true, + userString = '', + userPwd = '', + registerUser = true +}: { + channel: string + contractName: string + connProfilePath: string + networkName: string + mspId?: string + discoveryEnabled?: boolean + logger?: any + userString?: string + userPwd?: string + registerUser?: boolean +}): Promise<{ gateway: Gateway; contract: Contract; wallet: any }> { + // load the network configuration + const ccpPath = path.resolve(__dirname, connProfilePath) + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) + // Create a new file system based wallet for managing identities. + // const walletPath = process.env.WALLET_PATH + // ? process.env.WALLET_PATH + // : path.join(__dirname, '../', `wallet-${networkName}`) + + if (!userString) { + userString = `user1` + userPwd = `user1pw` + } + + const wallet = await walletSetup(networkName, ccp, mspId, userString, userPwd, false, false, registerUser, logger) + // Check to see if we've already enrolled the user. + const identity = await wallet.get(userString) + if (!identity) { + logger.info( + `An identity for the user "${userString}" does not exist in the wallet` + ) + logger.info('Run the registerUser.ts application before retrying') + } + // Create a new gateway for connecting to our peer node. + const gateway = new Gateway() + await gateway.connect(ccp, { + wallet, + identity: identity, + discovery: { + enabled: discoveryEnabled, + asLocalhost: process.env.LOCAL === 'false' ? false : true + } + }) + const network = await gateway.getNetwork(channel) + // Get the contract from the network. + const contract = network.getContract(contractName) + return { gateway, contract, wallet } +} + +async function query( + invocationSpec: InvocationSpec, + connProfilePath: string, + networkName: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console, + userString = '', + registerUser = true +): Promise { + logger.debug('Running invoke on fabric network') + try { + logger.debug( + `QUERY: ${JSON.stringify( + invocationSpec + )} connProfilePath: ${connProfilePath} networkName ${networkName} ` + ) + const { contract, gateway } = await fabricHelper({ + channel: invocationSpec.channel, + contractName: invocationSpec.contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: mspId, + logger: logger, + userString: userString, + registerUser: registerUser + }) + const read = await contract.evaluateTransaction(invocationSpec.ccFunc, ...invocationSpec.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`State From Network:`, state) + } else { + logger.debug(`No State from network`) + } + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + logger.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +async function invoke( + invocationSpec: InvocationSpec, + connProfilePath: string, + networkName: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console, + userString = '', + registerUser = true +): Promise { + logger.debug('Running invoke on fabric network') + try { + const { contract, gateway } = await fabricHelper({ + channel: invocationSpec.channel, + contractName: invocationSpec.contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: mspId, + logger: logger, + userString: userString, + registerUser: registerUser + }) + logger.debug( + `CCFunc: ${invocationSpec.ccFunc} 'CCArgs: ${JSON.stringify(invocationSpec.args)}` + ) + const read = await contract.submitTransaction(invocationSpec.ccFunc, ...invocationSpec.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +const getKeyAndCertForRemoteRequestbyUserName = async ( + wallet: any, + username: string +): Promise<{ key: ICryptoKey; cert: any }> => { + if (!wallet) { + throw new Error('No wallet passed') + } + if (!username) { + throw new Error('No username passed') + } + const identity = await wallet.get(username) + if (!identity) { + throw new Error( + 'Identity for username ' + username + ' not present in wallet' + ) + } + // Assume the identity is of type 'fabric-network.X509Identity' + const privKey = Utils.newCryptoSuite().createKeyFromRaw( + identity.credentials.privateKey + ) + return { key: privKey, cert: identity.credentials.certificate } +} + +const getWalletForNetwork = async ( + networkName: string, +) => { + const walletPath = process.env.WALLET_PATH + ? process.env.WALLET_PATH + : path.join(__dirname, '../', `wallet-${networkName}`) + + const wallet = await Wallets.newFileSystemWallet(walletPath) + return wallet +} + + +export { + getUserCertBase64, + walletSetup, + invoke, + query, + enrollAndRecordWalletIdentity, + fabricHelper, + generateMembership, + generateAccessControl, + getKeyAndCertForRemoteRequestbyUserName, + getCredentialPath, + getCurrentNetworkCredentialPath, + generateVerificationPolicy +} diff --git a/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts b/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts new file mode 100644 index 0000000000..624164d8be --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts @@ -0,0 +1,764 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { getKeyAndCertForRemoteRequestbyUserName, fabricHelper, invoke, query, InvocationSpec } from './fabric-functions' +import { AssetPledge } from "@hyperledger/cacti-weaver-protos-js/common/asset_transfer_pb" +import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric' +import * as crypto from 'crypto' +import { promisify } from 'util' +import * as fs from 'fs' +import * as path from 'path' +import * as dotenv from 'dotenv' +import logger from './logger' +dotenv.config({ path: path.resolve(__dirname, '../../.env') }) + + +// UPDATE Following if new env variable or config variable is added. +// Valid keys for .env +const validKeys = [ + 'DEFAULT_CHANNEL', + 'DEFAULT_CHAINCODE', + 'MEMBER_CREDENTIAL_FOLDER', + 'LOCAL', + 'DEFAULT_APPLICATION_CHAINCODE', + 'CONFIG_PATH', + 'REMOTE_CONFIG_PATH', + 'CHAINCODE_PATH' +] +// Valid keys for config +const configKeys = ['connProfilePath', 'relayEndpoint', 'mspId', 'channelName', 'chaincode', 'aclPolicyPrincipalType'] + +const signMessage = (message, privateKey) => { + const sign = crypto.createSign('sha256') + sign.write(message) + sign.end() + return sign.sign(privateKey) +} + +// Basic function to add assets to network, it assumes function is CreateAsset +// TODO: Pass function name as parameter +const addAssets = ({ + dataFilePath, + networkName, + connProfilePath, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + channelName, + contractName, + ccFunc, + ccType, + logger +}: { + dataFilePath: string + networkName: string + connProfilePath: string + invocationSpec?: InvocationSpec + mspId?: string + channelName?: string + contractName?: string + ccFunc?: string + ccType: string + logger?: any +}): void => { + const filepath = path.resolve(dataFilePath) + const data = JSON.parse(fs.readFileSync(filepath).toString()) + const valuesList = Object.entries(data) + valuesList.forEach(async (item: [string, string]) => { + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: channelName, + contractName: contractName + ? contractName + : 'simpleasset', + ccFunc: '', + args: [] + } + + const { gateway, contract, wallet } = await fabricHelper({ + channel: channelName, + contractName: contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: mspId, + userString: item[1]['owner'], + registerUser: false + }) + const userId = await wallet.get(item[1]['owner']) + const userCert = Buffer.from((userId).credentials.certificate).toString('base64') + + if (ccType == 'bond') { + currentQuery.ccFunc = 'CreateAsset' + currentQuery.args = [...currentQuery.args, item[1]['assetType'], item[1]['id'], userCert, item[1]['issuer'], item[1]['facevalue'], item[1]['maturitydate']] + } else if (ccType == 'token') { + currentQuery.ccFunc = 'IssueTokenAssets' + currentQuery.args = [...currentQuery.args, item[1]['tokenassettype'], item[1]['numunits'], userCert] + } else { + throw new Error(`Unrecognized asset category: ${ccType}`) + } + console.log(currentQuery) + try { + const read = await contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } + }) +} + + +// Basic function to pledge an asset in one network to another, it assumes function is PledgeAsset +// TODO: Pass function name as parameter +const pledgeAsset = async ({ + dataFilePath, + sourceNetworkName, + destNetworkName, + recipient, + expirySecs, + connProfilePath, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + channelName, + contractName, + ccFunc, + ccType, + assetOwner, + assetRef, + assetUnits, + logger +}: { + dataFilePath: string + sourceNetworkName: string + destNetworkName: string + recipient: string + expirySecs: number + connProfilePath: string + invocationSpec?: InvocationSpec + mspId?: string + channelName?: string + contractName?: string + ccFunc?: string + ccType: string + assetOwner: string + assetRef: string + assetUnits: number + logger?: any +}): Promise => { + const filepath = path.resolve(dataFilePath) + const data = JSON.parse(fs.readFileSync(filepath).toString()) + let item + if (assetRef) { + item = data[assetRef] + if (!item) { + throw new Error(`Cannot find asset ref ${assetRef} in file ${filepath}`) + } + } else if (assetOwner) { + item = data[assetOwner] + if (!item) { + throw new Error(`Cannot find asset owner ${assetOwner} in file ${filepath}`) + } + } else { + throw new Error(`Neither asset owner nor reference is supplied`) + } + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: channelName, + contractName: contractName + ? contractName + : 'simpleasset', + ccFunc: '', + args: [] + } + + const { gateway, contract, wallet } = await fabricHelper({ + channel: channelName, + contractName: contractName, + connProfilePath: connProfilePath, + networkName: sourceNetworkName, + mspId: mspId, + userString: item['owner'], + registerUser: false + }) + const recipientCert = getUserCertFromFile(recipient, destNetworkName) + const expirationTime = (Math.floor(Date.now()/1000 + expirySecs)).toString() + + if (ccType == 'bond') { + currentQuery.ccFunc = 'PledgeAsset' + currentQuery.args = [...currentQuery.args, item['assetType'], item['id'], destNetworkName, recipientCert, expirationTime] + } else if (ccType == 'token') { + currentQuery.ccFunc = 'PledgeTokenAsset' + currentQuery.args = [...currentQuery.args, item['tokenassettype'], '' + assetUnits, destNetworkName, recipientCert, expirationTime] + } else { + throw new Error(`Unrecognized/unsupported asset category: ${ccType}`) + } + console.log(currentQuery) + try { + const read = await contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +// Used to obtain remote network user certificate from '${networkId}_UsersAndCerts.json' file. +// This is called during Pledge to get the recipientCert, and during Claim to get the pledgerCert. +const getUserCertFromFile = ( + remoteUser: string, + remoteNetworkId: string +) => { + const usersAndCertsFile = remoteNetworkId + '_UsersAndCerts.json' + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, '..') + : path.join(__dirname, '../data', 'credentials', '..') + try { + const dirPath = path.resolve(credentialsPath, 'remoteNetworkUsers') + const filepath = path.resolve(dirPath, usersAndCertsFile) + const usersAndCertsJSON = JSON.parse(fs.readFileSync(filepath).toString()) + logger.debug(`credentialsPath: ${credentialsPath} and usersAndCertsFile: ${usersAndCertsFile}`) + + if (!usersAndCertsJSON[remoteUser]) { + logger.error( + `User: ${remoteUser} does not exist in the file ${usersAndCertsFile}.` + ) + return '' + } + logger.debug(`remoteUser: ${remoteUser} and certificate: ${usersAndCertsJSON[remoteUser]}`) + return usersAndCertsJSON[remoteUser] + } catch (err) { + logger.error(`User: ${remoteUser} does not exist in the file ${usersAndCertsFile}.`) + return '' + } +} + +// Used to store the network user certificate to the file '${networkId}_UsersAndCerts.json'. +// This is used during Pledge to get the recipientCert, and during Claim to get the pledgerCert. +const saveUserCertToFile = ( + remoteUser: string, + remoteNetworkId: string +) => { + const usersAndCertsFile = remoteNetworkId + '_UsersAndCerts.json' + let usersAndCertsJSON = {} + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, '..') + : path.join(__dirname, '../data', 'credentials', '..') + // Don't create the directory 'remoteNetworkUsers' inside 'data/credentials' since each entry there represents + // a network. Instead, create this directory inside 'data' itself. + try { + const dirPath = path.resolve(credentialsPath, 'remoteNetworkUsers') + const filepath = path.resolve(dirPath, usersAndCertsFile) + logger.debug(`credentialsPath: ${credentialsPath} and usersAndCertsFile: ${usersAndCertsFile}`) + + if (!fs.existsSync(dirPath)) { + logger.debug(`Creating directory ${dirPath}`) + fs.mkdirSync(dirPath, { recursive: true }) + } + + if (fs.existsSync(filepath)) { + logger.debug(`Reading contents of the file ${filepath}`) + usersAndCertsJSON = JSON.parse(fs.readFileSync(filepath).toString()) + } + + const remoteUserId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + remoteNetworkId + '/' + remoteUser + '.id').toString()) + const remoteUserCertBase64 = Buffer.from(remoteUserId.credentials.certificate).toString('base64') + + usersAndCertsJSON[remoteUser] = remoteUserCertBase64 + fs.writeFileSync( + path.resolve(filepath), + JSON.stringify(usersAndCertsJSON) + ) + } catch (err) { + logger.error(`User: ${remoteUser} certificate cannot be saved to the file ${usersAndCertsFile}.`) + } +} + +// Basic function to query asset pledge details from a network, it assumes function is GetAssetPledgeStatus +// TODO: Pass function name as parameter +const getAssetPledgeDetails = async ({ + sourceNetworkName, + pledger, + pledgerCert, + destNetworkName, + recipient, + recipientCert, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + ccFunc, + pledgeId, + logger +}: { + sourceNetworkName: string + pledger: string + pledgerCert: string + destNetworkName: string + recipient: string + recipientCert: string + invocationSpec?: InvocationSpec + mspId?: string + ccFunc?: string + pledgeId: string + logger?: any +}): Promise => { + const netConfig = getNetworkConfig(sourceNetworkName) + + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: netConfig.channelName, + contractName: netConfig.chaincode + ? netConfig.chaincode + : 'simpleasset', + ccFunc: '', + args: [] + } + + const { gateway, contract, wallet } = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: sourceNetworkName, + mspId: netConfig.mspId, + userString: pledger, + registerUser: false + }) + if (!pledgerCert) { + const pledgerId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + sourceNetworkName + '/' + pledger + '.id').toString()) + pledgerCert = Buffer.from(pledgerId.credentials.certificate).toString('base64') + } + if (!recipientCert) { + const recipientId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + destNetworkName + '/' + recipient + '.id').toString()) + recipientCert = Buffer.from(recipientId.credentials.certificate).toString('base64') + } + + currentQuery.ccFunc = 'GetAssetPledgeStatus' + currentQuery.args = [...currentQuery.args, pledgeId, pledgerCert, destNetworkName, recipientCert] + console.log(currentQuery) + try { + const read = await contract.evaluateTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +// Basic function to query asset pledge details from a network, it assumes function is GetAssetPledgeDetails +// TODO: Pass function name as parameter +const getLocalAssetPledgeDetails = async ({ + sourceNetworkName, + pledgeId, + caller, + ccType, + ccFunc, + logger +}: { + sourceNetworkName: string + pledgeId: string + caller: string + ccType?: string + ccFunc?: string + logger?: any +}): Promise => { + const netConfig = getNetworkConfig(sourceNetworkName) + + const currentQuery = { + channel: netConfig.channelName, + contractName: netConfig.chaincode + ? netConfig.chaincode + : 'simpleasset', + ccFunc: '', + args: [] + } + + if (ccFunc) { + currentQuery.ccFunc = ccFunc + } else if (ccType && ccType == 'token') { + currentQuery.ccFunc = 'GetTokenAssetPledgeDetails' + } else { + currentQuery.ccFunc = 'GetAssetPledgeDetails' + } + currentQuery.args = [...currentQuery.args, pledgeId] + console.log(currentQuery) + try { + const pledgeDetails = await query(currentQuery, + netConfig.connProfilePath, + sourceNetworkName, + netConfig.mspId, + logger, + caller, + false + ) + const pledgeDetailBytes = Buffer.from(pledgeDetails, 'base64') + const pledgeDetailsProto = AssetPledge.deserializeBinary(pledgeDetailBytes) + return pledgeDetailsProto + } catch (error) { + console.error(`Failed to get pledge details: ${error}`) + throw new Error(error) + } +} + +// Basic function to add data to network, it assumes function is Create +// TODO: Pass function name as parameter +const addData = ({ + filename, + networkName, + connProfilePath, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + logger +}: { + filename: string + networkName: string + connProfilePath: string + invocationSpec?: InvocationSpec + mspId?: string + logger?: any +}): void => { + const filepath = path.resolve(__dirname, '..', 'data', filename) + const data = JSON.parse(fs.readFileSync(filepath).toString()) + const valuesList = Object.entries(data) + valuesList.forEach((item: [string, string]) => { + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: process.env.DEFAULT_CHANNEL + ? process.env.DEFAULT_CHANNEL + : 'mychannel', + contractName: process.env.DEFAULT_APPLICATION_CHAINCODE + ? process.env.DEFAULT_APPLICATION_CHAINCODE + : 'simplestate', + ccFunc: process.env.DEFAULT_APPLICATION_FUNC + ? process.env.DEFAULT_APPLICATION_FUNC + : 'Create', + args: [] + } + currentQuery.args = [...currentQuery.args, item[0], item[1]] + invoke(currentQuery, connProfilePath, networkName, mspId, logger) + }) +} + +// A better way to handle errors for promises +function handlePromise(promise: Promise): Promise<[T?, Error?]> { + const result: Promise<[T?, Error?]> = promise + .then(data => { + const response: [T?, Error?] = [data, undefined] + return response + }) + .catch(error => Promise.resolve([undefined, error])) + return result +} + +// Necessary until gRPC provides a native async friendly solution https://github.com/grpc/grpc-node/issues/54 +function promisifyAll(client): any { + const to = {} + for (const k in client) { + if (typeof client[k] != 'function') continue + to[k] = promisify(client[k].bind(client)) + } + return to +} + +const readJSONFromFile = (jsonfile, logger = console) => { + let data = null + const filepath = path.resolve(jsonfile) + logger.debug('jsonfile is ' + jsonfile) + logger.debug('filepath is ' + filepath) + + try { + const contents = fs.readFileSync(filepath).toString() + logger.debug('contents ' + contents) + data = JSON.parse(contents) + logger.debug('data - ' + JSON.stringify(data)) + } catch (e) { + logger.debug('Error ' + e.message + ' while parsing JSON config file') + throw e + } + return data +} + +// Used for getting network configuration from config.json file. +const getNetworkConfig = ( + networkId: string +): { relayEndpoint?: string; connProfilePath: string; username?: string; mspId?:string; aclPolicyPrincipalType?: string; channelName?: string; chaincode?: string } => { + const configPath = process.env.CONFIG_PATH + ? path.join(process.env.CONFIG_PATH) + : path.join(__dirname, '../../config.json') + try { + const configJSON = JSON.parse(fs.readFileSync(configPath).toString()) + if (!configJSON[networkId]) { + logger.error( + `Network: ${networkId} does not exist in the config.json file` + ) + return { relayEndpoint: '', connProfilePath: '', username: '', mspId: '', aclPolicyPrincipalType: '', channelName: '', chaincode: '' } + } + return configJSON[networkId] + } catch (err) { + logger.error(`Network: ${networkId} does not exist in the config.json file`) + return { relayEndpoint: '', connProfilePath: '', username: '', mspId: '', aclPolicyPrincipalType: '', channelName: '', chaincode: '' } + } +} + +// Used for getting network configuration from config.json file. +const getChaincodeConfig = ( + chaincodeId: string, + chaincodeFunc: string +): { args: Array; replaceIndices: Array } => { + const ccPath = process.env.CHAINCODE_PATH + ? path.join(process.env.CHAINCODE_PATH) + : path.join(__dirname, '../../chaincode.json') + try { + const ccJSON = JSON.parse(fs.readFileSync(ccPath).toString()) + if (!ccJSON[chaincodeId]) { + logger.error( + `Chaincode: ${chaincodeId} does not exist in the chaincode.json file` + ) + return { args: [], replaceIndices: [] } + } + if (!ccJSON[chaincodeId][chaincodeFunc]) { + logger.error( + `Chaincode: ${chaincodeId} does not have a ${chaincodeFunc} function attribute in the chaincode.json file` + ) + return { args: [], replaceIndices: [] } + } + return ccJSON[chaincodeId][chaincodeFunc] + } catch (err) { + logger.error(`Chaincode: ${chaincodeId} does not exist in the chaincode.json file`) + return { args: [], replaceIndices: [] } + } +} + +// Update view address if needed +const generateViewAddress = async ( + viewAddress: string, + sourceNetwork: string, + destNetwork: string, + logger?: any +): Promise => { + if (!viewAddress || viewAddress.length === 0) { + throw new Error('Empty view address') + } + if (viewAddress.indexOf('#') >= 0) { + return viewAddress + } + if (viewAddress.indexOf('GetAssetClaimStatus') >= 0 || viewAddress.indexOf('GetTokenAssetClaimStatus') >= 0) { + // Get asset pledge details + let ccFunc + if (viewAddress.indexOf('GetAssetClaimStatus') >= 0) { + ccFunc = 'GetAssetClaimStatus' + } else { + ccFunc = 'GetTokenAssetClaimStatus' + } + const addressParts = viewAddress.substring(viewAddress.indexOf(ccFunc) + ccFunc.length + 1).split(':') + if (addressParts.length != 6) { + throw new Error(`Expected 6 arguments for ${ccFunc}; found ${addressParts.length}`) + } + if (addressParts[5] != sourceNetwork) { + throw new Error(`Passed source network ID ${sourceNetwork} does not match last chaincode argument in view address ${addressParts[5]}`) + } + const pledgeDetails = await getAssetPledgeDetails({ + sourceNetworkName: addressParts[5], + pledger: '', + pledgerCert: addressParts[4], + destNetworkName: destNetwork, + recipient: '', + recipientCert: addressParts[3], + pledgeId: addressParts[0], + logger: logger + }) + return viewAddress + ':' + deserializeAssetPledge(pledgeDetails).getExpirytimesecs() + } else { + return viewAddress + } +} + +function deserializeAssetPledge(pledgeDetails) { + const pledgeDetailBytes = Buffer.from(pledgeDetails, 'base64') + const pledgeDetailsProto = AssetPledge.deserializeBinary(pledgeDetailBytes) + return pledgeDetailsProto +} + +// Used for creating view address for interop call using remote-network-config.json +const generateViewAddressFromRemoteConfig = ( + networkId: string, + funcName: string, + funcArgs: Array +): any => { + const configPath = process.env.REMOTE_CONFIG_PATH + ? path.join(process.env.REMOTE_CONFIG_PATH) + : path.join(__dirname, '../../remote-network-config.json') + try { + const configJSON = JSON.parse(fs.readFileSync(configPath).toString()) + if (!configJSON[networkId]) { + logger.error( + `Error: ${networkId} does not exist in the remote-network-config.json file` + ) + throw new Error(`Error: ${networkId} does not exist in the remote-network-config.json file`) + } + + const remoteNetConfig = configJSON[networkId] + let address = remoteNetConfig.relayEndpoint + '/' + networkId + if (remoteNetConfig.type == "fabric") { + address = address + '/' + remoteNetConfig.channelName + ':' + + remoteNetConfig.chaincode + ':' + funcName + ':' + funcArgs.join(':') + } else if (remoteNetConfig.type == "corda") { + address = address + '/' + remoteNetConfig.partyEndPoint + '#' + + remoteNetConfig.flowPackage + "." + funcName + ":" + funcArgs.join(':') + } else { + logger.error(`Error: remote network ${remoteNetConfig.type} not supported.`) + throw new Error(`Error: remote network ${remoteNetConfig.type} not supported.`) + } + console.log(`Interop query, funcName: ${funcName} \n funcArgs: ${funcArgs} \n and address: ${address}`) + + return address + } catch (err) { + logger.error(`Error: ${err}`) + throw new Error(err) + } +} + + +// Used for creating view address for interop call using remote-network-config.json +const interopHelper = async ( + networkName: string, + viewAddress: string, + appChaincodeId: string, + applicationFunction: string, + applicationArgs: Array, + replaceIndices: Array, + options: any, // For TLS +): Promise => { + const netConfig = getNetworkConfig(networkName) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + throw new Error(`No valid config entry found for ${networkName}`) + } + + const { gateway, wallet, contract } = await fabricHelper({ + channel: netConfig.channelName, + contractName: process.env.DEFAULT_CHAINCODE ? process.env.DEFAULT_CHAINCODE : 'interop', + connProfilePath: netConfig.connProfilePath, + networkName, + mspId: netConfig.mspId, + logger, + discoveryEnabled: true, + userString: options['user'] + }) + + const [keyCert, keyCertError] = await handlePromise( + getKeyAndCertForRemoteRequestbyUserName(wallet, options['user']) + ) + if (keyCertError) { + throw new Error(`Error getting key and cert ${keyCertError}`) + } + logger.info(`Starting Interop Query`) + + let relayTlsCAFiles = [] + if (options['relay-tls-ca-files']) { + relayTlsCAFiles = options['relay-tls-ca-files'].split(':') + } + try { + const invokeObject = { + channel: netConfig.channelName, + ccFunc: applicationFunction, + ccArgs: applicationArgs, + contractName: appChaincodeId + } + console.log(invokeObject) + const interopFlowResponse = await InteroperableHelper.interopFlow( + //@ts-ignore this comment can be removed after using published version of interop-sdk + contract, + networkName, + invokeObject, + netConfig.mspId, + netConfig.relayEndpoint, + replaceIndices, + [{ + address: viewAddress, + Sign: true + }], + keyCert, + [], + false, + options['relay-tls'] === 'true', + relayTlsCAFiles, + options['e2e-confidentiality'] === 'true', + gateway + ) + logger.info( + `View from remote network: ${JSON.stringify( + interopFlowResponse.views[0].toObject() + )}. Interop Flow result: ${interopFlowResponse.result || 'successful'}` + ) + logger.debug(`ViewB64: ${Buffer.from(interopFlowResponse.views[0].serializeBinary()).toString('base64')}`) + const remoteValue = (options['e2e-confidentiality'] === 'true' ? + InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0], keyCert.key.toBytes()) : + InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0]) + ) + if (remoteValue.contents) { + logger.debug(`ViewB64Contents: ${Buffer.from(remoteValue.contents).toString('base64')}`) + } + logger.info( + `Called Function ${applicationFunction}. With Args: ${invokeObject.ccArgs} ${remoteValue.data}` + ) + await gateway.disconnect() + return remoteValue.data + } catch (e) { + logger.error(`Error verifying and storing state`) + logger.error(`Error verifying and storing state: ${e}`) + return "" + } +} + + + +export { + addData, + handlePromise, + promisifyAll, + readJSONFromFile, + signMessage, + getNetworkConfig, + getUserCertFromFile, + saveUserCertToFile, + getChaincodeConfig, + validKeys, + configKeys, + addAssets, + pledgeAsset, + getAssetPledgeDetails, + getLocalAssetPledgeDetails, + generateViewAddress, + generateViewAddressFromRemoteConfig, + interopHelper +} diff --git a/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts b/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts new file mode 100644 index 0000000000..b85bbc1db6 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts @@ -0,0 +1,230 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as fs from 'fs' +import * as path from 'path' +import { + invoke, + getCurrentNetworkCredentialPath, + getCredentialPath, + fabricHelper +} from '../fabric-functions' +import { handlePromise, getNetworkConfig } from '../helpers' +import { MembershipManager } from '@hyperledger/cacti-weaver-sdk-fabric' + +const helperInvoke = async (userId, ccFunc, ccArg, ...args) => { + const [contractName, channelName, connProfilePath, networkName, logger] = args + const [invokeResponse, invokeError] = await handlePromise( + invoke( + { + contractName, + channel: channelName, + ccFunc: ccFunc, + args: [ccArg] + }, + connProfilePath, + networkName, + global.__DEFAULT_MSPID__, + logger, + userId, + (userId === '') + ) + ) + logger.debug(`${ccFunc} Invoke ${JSON.stringify(invokeResponse)}`) + if (invokeError) { + logger.error(`${ccFunc} Invoke Error: ${ccFunc}: ${ccArg}`) + throw new Error(`${ccFunc} Invoke Error ${invokeError}`) + } else { + logger.info(`Successfully invoked ${ccFunc}`) + } +} + +const configureNetwork = async (mainNetwork: string, members: Array = [global.__DEFAULT_MSPID__], logger: any = console, iinAgent: boolean = false) => { + const networkEnv = getNetworkConfig(mainNetwork) + logger.debug(`NetworkEnv: ${JSON.stringify(networkEnv)}`) + if (!networkEnv.relayEndpoint || !networkEnv.connProfilePath) { + logger.error( + 'Please use a valid --local-network. If valid network please check if your environment variables are configured properly' + ) + return + } + + const credentialFolderPath = getCredentialPath() + const networkFolders = fs + .readdirSync(credentialFolderPath, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .map(item => item.name) + // Reorder the array so that the local network is the first element + // We need to record local membership before recording other networks' memberships + networkFolders.splice(networkFolders.indexOf(mainNetwork), 1) + networkFolders.splice(0, 0, mainNetwork) + + for (const index in networkFolders) { + const network = networkFolders[index] + if (network === mainNetwork) { + // A network needs to load/record only other networks' credentials + await loadLocalHelper( + networkEnv.connProfilePath, + mainNetwork, + process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', + process.env.DEFAULT_CHAINCODE + ? process.env.DEFAULT_CHAINCODE + : 'interop', + members, + logger + ) + continue; + } + const accessControlPath = path.join( + getCurrentNetworkCredentialPath(network), + 'access-control.json' + ) + let membershipPath = "" + if (!network.startsWith('network')) { + membershipPath = path.join( + getCurrentNetworkCredentialPath(network), + 'membership.json' + ) + } else if (iinAgent) { + membershipPath = path.join( + getCurrentNetworkCredentialPath(network), + 'attested-membership-' + mainNetwork + '.proto.serialized' + ) + } + const verificationPolicyPath = path.join( + getCurrentNetworkCredentialPath(network), + 'verification-policy.json' + ) + if ( + !fs.existsSync(accessControlPath) || + !fs.existsSync(verificationPolicyPath) || + (membershipPath !== "" && !fs.existsSync(membershipPath)) + ) { + logger.error(`Missing credential file for network: ${network}`) + } else { + await configureNetworkHelper( + networkEnv.connProfilePath, + mainNetwork, + process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', + process.env.DEFAULT_CHAINCODE + ? process.env.DEFAULT_CHAINCODE + : 'interop', + network, + accessControlPath, + membershipPath, + verificationPolicyPath, + logger, + iinAgent + ) + } + } +} + +const loadLocalHelper = async ( + connProfilePath: string, + networkName: string, + channelName: string, + contractName: string, + members: Array, + logger: any = console +): Promise => { + //const localMembership = Buffer.from(fs.readFileSync(localMembershipPath)).toString() + const { gateway } = await fabricHelper({ + channel: channelName, + contractName: contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: global.__DEFAULT_MSPID__, + userString: 'networkadmin', + registerUser: false + }) + try { + const response = await MembershipManager.createLocalMembership(gateway, members, networkName, channelName, contractName) + logger.info('CreateLocalMembership Successful.') + } catch (e) { + logger.error(e) + logger.info('CreateLocalMembership attempting Update') + const response = await MembershipManager.updateLocalMembership(gateway, members, networkName, channelName, contractName) + logger.info('Update Local Memebrship response: success: ', response) + } +} + +const configureNetworkHelper = async ( + connProfilePath: string, + networkName: string, + channelName: string, + contractName: string, + targetNetwork: string, + accessControlPath: string, + membershipPath: string, + verificationPolicyPath: string, + logger: any = console, + iinAgent: boolean = false +): Promise => { + logger.info(`Target Network: ${targetNetwork}`) + const accessControl = Buffer.from( + fs.readFileSync(accessControlPath) + ).toString() + + const verificationPolicy = Buffer.from( + fs.readFileSync(verificationPolicyPath) + ).toString() + + const helperInvokeArgs = [ + contractName, + channelName, + connProfilePath, + networkName, + logger + ] + + const adminUser = 'networkadmin' + + try { + await helperInvoke( + adminUser, + 'CreateAccessControlPolicy', + accessControl, + ...helperInvokeArgs + ) + } catch (e) { + logger.info('CreateAccessControlPolicy attempting Update') + await helperInvoke( + adminUser, + 'UpdateAccessControlPolicy', + accessControl, + ...helperInvokeArgs + ) + } + try { + await helperInvoke( + adminUser, + 'CreateVerificationPolicy', + verificationPolicy, + ...helperInvokeArgs + ) + } catch (e) { + logger.info('CreateVerificationPolicy attempting Update') + await helperInvoke( + adminUser, + 'UpdateVerificationPolicy', + verificationPolicy, + ...helperInvokeArgs + ) + } + if (iinAgent || !targetNetwork.startsWith('network')) { + const membership = Buffer.from(fs.readFileSync(membershipPath)).toString() + const memberRecordingUser = iinAgent ? 'iinagent': adminUser // HACK until we add IIN Agents for Corda networks + try { + await helperInvoke(memberRecordingUser, 'CreateMembership', membership, ...helperInvokeArgs) + } catch (e) { + logger.info('CreateMembership attempting Update') + await helperInvoke(memberRecordingUser, 'UpdateMembership', membership, ...helperInvokeArgs) + } + } +} + +export { configureNetworkHelper, configureNetwork } diff --git a/weaver/core/drivers/fabric-driver/server/helpers/logger.ts b/weaver/core/drivers/fabric-driver/server/helpers/logger.ts new file mode 100644 index 0000000000..7b14c5a377 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/logger.ts @@ -0,0 +1,29 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as winston from 'winston' +import * as path from 'path' +const { format, transports } = winston + +const logFormat = format.printf( + info => `${info.timestamp} ${info.level} [${info.label}]: ${info.message}` +) + +const logger = winston.createLogger({ + format: format.combine( + format.label({ label: path.basename(process.mainModule.filename) }), + format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), + format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] }) + ), + transports: [ + new transports.Console({ + format: format.combine(format.colorize(), logFormat) + }) + ], + exitOnError: false +}) + +export default logger diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts new file mode 100644 index 0000000000..d0240049d6 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -0,0 +1,196 @@ +import ack_pb from '@hyperledger/cacti-weaver-protos-js/common/ack_pb'; +import eventsPb from '@hyperledger/cacti-weaver-protos-js/common/events_pb'; +import events_grpc_pb from '@hyperledger/cacti-weaver-protos-js/relay/events_grpc_pb'; +import queryPb from '@hyperledger/cacti-weaver-protos-js/common/query_pb'; +import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric'; +import { getDriverKeyCert } from "./walletSetup"; +import { DBConnector, DBKeyNotFoundError, LevelDBConnector } from "./dbConnector"; +import { checkIfArraysAreEqual, handlePromise, relayCallback } from "./utils"; +import { registerListenerForEventSubscription, unregisterListenerForEventSubscription } from "./listener"; +import { getNetworkGateway } from "./fabric-code"; +import { Gateway, Network, Contract } from "fabric-network"; +import state_pb from '@hyperledger/cacti-weaver-protos-js/common/state_pb'; +import driverPb from '@hyperledger/cacti-weaver-protos-js/driver/driver_pb'; +import logger from './logger'; + +import { getNetworkConfig } from './helpers/helpers' +import { AssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' + +import fs from 'fs'; +import path from 'path'; +import { fabricHelper } from './helpers/fabric-functions'; + +const DB_NAME: string = "driverdb"; +const DRIVER_ERROR_CONSTANTS = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../constants/driver-error-constants.json'), + ).toString(), +); + +async function performLockHelper( + performLockRequest: driverPb.PerformLockRequest, + networkName: string +): Promise { + + + // Locker and Recipient + const locker = performLockRequest['locker']; + const recipient = performLockRequest['recipient']; + let hashFn = performLockRequest['hash_fn']; + let hashBase64 = performLockRequest['hashBase64']; + + // Hash + let hash: HashFunctions.Hash + if (hashFn == 'SHA512') { + hash = new HashFunctions.SHA512() + } else { + hash = new HashFunctions.SHA256() + } + + if (hashBase64) { + hash.setSerializedHashBase64(hashBase64) + } + else { + logger.info(`No hash provided, using random preimage`) + } + + // Timeout + var timeout = 0, timeout2 = 0; + const currTime = Math.floor(Date.now() / 1000); + if (performLockRequest['timeout-epoch']) { + let duration = performLockRequest['timeout-epoch'] - currTime + timeout = performLockRequest['timeout-epoch'] + timeout2 = performLockRequest['timeout-epoch'] + duration + } + else if (performLockRequest['timeout-duration']) { + timeout = currTime + performLockRequest['timeout-duration'] + timeout2 = currTime + 2 * performLockRequest['timeout-duration'] + } + + const params = performLockRequest['param'].split(':') + + const netConfig = getNetworkConfig(performLockRequest['target-network']) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + console.error( + `Please use a valid --target-network. No valid environment found for ${performLockRequest['target-network']} ` + ) + return + } + + const network = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: performLockRequest['target-network'], + mspId: netConfig.mspId, + userString: locker + }) + + const lockerId = await network.wallet.get(locker) + const lockerCert = Buffer.from((lockerId).credentials.certificate).toString('base64') + + const recipientId = await network.wallet.get(recipient) + const recipientCert = Buffer.from((recipientId).credentials.certificate).toString('base64') + + var funcToCall, asset + + if (performLockRequest['fungible']) { + funcToCall = AssetManager.createFungibleHTLC + asset = 'Fungible Asset' + } else { + funcToCall = AssetManager.createHTLC + asset = 'Asset' + } + + console.info(`Asset Exchange: Lock ${asset}:\n`); + + try { + console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) + const res = await funcToCall(network.contract, + params[0], + params[1], + recipientCert, + hash, + timeout, + null) + if (!res.result) { + throw new Error() + } + console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) + console.info('Asset Exchange: Lock Complete.') + } catch (error) { + console.error(`Could not Lock ${asset} in ${performLockRequest['target-network']}`) + } + + // await new Promise(f => setTimeout(f, performLockRequest['timeout-duration'] * 1000 + 3000)); + + await network.gateway.disconnect() + console.log('Gateways disconnected.') + + + // const viewPayload: state_pb.ViewPayload = performLockRequest.getViewPayload(); + // const ctx: eventsPb.ContractTransaction = writeExternalStateMessage.getCtx(); + // const keyCert = await getDriverKeyCert(); + + // const requestId: string = viewPayload.getRequestId(); + // if (!viewPayload.getError()) { + + // let interopArgIndices = [], viewsSerializedBase64 = [], addresses = [], viewContentsBase64 = []; + // const view: state_pb.View = viewPayload.getView(); + + // const result = InteroperableHelper.getResponseDataFromView(view, keyCert.key.toBytes()); + // if (result.contents) { + // viewContentsBase64.push(result.contents); + // } else { + // viewContentsBase64.push([]); + // } + + // interopArgIndices.push(ctx.getReplaceArgIndex()); + // addresses.push(result.viewAddress); + // viewsSerializedBase64.push(Buffer.from(viewPayload.getView().serializeBinary()).toString("base64")); + + // let ccArgsB64 = ctx.getArgsList(); + // let ccArgsStr = []; + // for (const ccArgB64 of ccArgsB64) { + // ccArgsStr.push(Buffer.from(ccArgB64).toString('utf8')); + // } + + // let gateway: Gateway = await getNetworkGateway(networkName); + // const network: Network = await gateway.getNetwork(ctx.getLedgerId()); + // const interopContract: Contract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); + + // const endorsingOrgs = ctx.getMembersList(); + // const invokeObject = { + // channel: ctx.getLedgerId(), + // ccFunc: ctx.getFunc(), + // ccArgs: ccArgsStr, + // contractName: ctx.getContractId() + // } + // logger.info(`writing external state to contract: ${ctx.getContractId()} with function: ${ctx.getFunc()}, and args: ${invokeObject.ccArgs} on channel: ${ctx.getLedgerId()}`); + + // const [ response, responseError ] = await handlePromise(InteroperableHelper.submitTransactionWithRemoteViews( + // interopContract, + // invokeObject, + // interopArgIndices, + // addresses, + // viewsSerializedBase64, + // viewContentsBase64, + // endorsingOrgs + // )); + // if (responseError) { + // logger.error(`Failed writing to the ledger with error: ${responseError}`); + // gateway.disconnect(); + // throw responseError; + // } + // logger.debug(`write successful`); + // gateway.disconnect(); + // } else { + // const errorString: string = `erroneous viewPayload identified in WriteExternalState processing`; + // logger.error(`error viewPayload.getError(): ${JSON.stringify(viewPayload.getError())}`); + // throw new Error(errorString); + // } +} + +export { + performLockHelper +} diff --git a/weaver/core/drivers/fabric-driver/server/server.ts b/weaver/core/drivers/fabric-driver/server/server.ts index c645caece3..d31c7805ff 100644 --- a/weaver/core/drivers/fabric-driver/server/server.ts +++ b/weaver/core/drivers/fabric-driver/server/server.ts @@ -19,6 +19,7 @@ import 'dotenv/config'; import { loadEventSubscriptionsFromStorage, monitorBlockForMissedEvents } from './listener' import { walletSetup } from './walletSetup'; import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery, writeExternalStateHelper } from "./events" +import { performLockHelper } from "./satp" import * as path from 'path'; import { handlePromise, relayCallback, getRelayClientForQueryResponse, getRelayClientForEventSubscription, delay } from './utils'; import { dbConnectionTest, eventSubscriptionTest } from "./tests" @@ -233,6 +234,27 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { callback(null, ack_err_response); }); }, + performLock: (call: { request: driverPb.PerformLockRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + performLockHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully written to the ledger'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, }); // Prepares required crypto material for communication with the fabric network diff --git a/weaver/core/relay/config/Dummy_Relay.toml b/weaver/core/relay/config/Dummy_Relay.toml index 125d18af27..bacb83f1fa 100644 --- a/weaver/core/relay/config/Dummy_Relay.toml +++ b/weaver/core/relay/config/Dummy_Relay.toml @@ -53,6 +53,6 @@ tls=false tlsca_cert_path="credentials/fabric_ca_cert.pem" [drivers.Dummy] hostname="localhost" -port="9092" +port="9090" tls=false tlsca_cert_path="credentials/fabric_ca_cert.pem" From 7c8dc1701eedec9701548e7b9e2bdce7e2c00e00 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Wed, 23 Aug 2023 12:20:05 +0100 Subject: [PATCH 35/59] Added the required functions to call back the gateway after the asset is locked. --- weaver/common/protos-go/build-protos.sh | 2 +- weaver/common/protos-js/build-protos.sh | 4 +- .../core/drivers/fabric-driver/server/satp.ts | 190 ++++++++---------- 3 files changed, 88 insertions(+), 108 deletions(-) diff --git a/weaver/common/protos-go/build-protos.sh b/weaver/common/protos-go/build-protos.sh index 0abbd7ac0c..19a6c4563a 100644 --- a/weaver/common/protos-go/build-protos.sh +++ b/weaver/common/protos-go/build-protos.sh @@ -12,6 +12,6 @@ protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go_out=$BUILDDIR protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go_out=$BUILDDIR --go_opt=paths=source_relative $PROTOSDIR/fabric/view_data.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go_out=$BUILDDIR --go_opt=paths=source_relative $PROTOSDIR/corda/view_data.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/networks/networks.proto -protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto PROTOSDIR/relay/satp.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/driver/driver.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/identity/agent.proto diff --git a/weaver/common/protos-js/build-protos.sh b/weaver/common/protos-js/build-protos.sh index 556e000112..d869c3bab9 100755 --- a/weaver/common/protos-js/build-protos.sh +++ b/weaver/common/protos-js/build-protos.sh @@ -17,7 +17,7 @@ grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR - grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/fabric/view_data.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/identity/agent.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/networks/networks.proto -grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto $PROTOSDIR/relay/satp.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto # Typescript Build @@ -27,5 +27,5 @@ protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDD protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/fabric/view_data.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/identity/agent.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/networks/networks.proto -protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto $PROTOSDIR/relay/satp.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index d0240049d6..cbea82e1cb 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -1,17 +1,8 @@ -import ack_pb from '@hyperledger/cacti-weaver-protos-js/common/ack_pb'; -import eventsPb from '@hyperledger/cacti-weaver-protos-js/common/events_pb'; -import events_grpc_pb from '@hyperledger/cacti-weaver-protos-js/relay/events_grpc_pb'; -import queryPb from '@hyperledger/cacti-weaver-protos-js/common/query_pb'; -import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric'; -import { getDriverKeyCert } from "./walletSetup"; -import { DBConnector, DBKeyNotFoundError, LevelDBConnector } from "./dbConnector"; -import { checkIfArraysAreEqual, handlePromise, relayCallback } from "./utils"; -import { registerListenerForEventSubscription, unregisterListenerForEventSubscription } from "./listener"; -import { getNetworkGateway } from "./fabric-code"; -import { Gateway, Network, Contract } from "fabric-network"; -import state_pb from '@hyperledger/cacti-weaver-protos-js/common/state_pb'; +import satp_pb from '@hyperledger/cacti-weaver-protos-js/relay/satp_pb'; +import satp_grpc_pb from '@hyperledger/cacti-weaver-protos-js/relay/satp_grpc_pb'; import driverPb from '@hyperledger/cacti-weaver-protos-js/driver/driver_pb'; import logger from './logger'; +import { credentials } from '@grpc/grpc-js'; import { getNetworkConfig } from './helpers/helpers' import { AssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' @@ -32,12 +23,19 @@ async function performLockHelper( networkName: string ): Promise { + let performLockRequest2 = {}; + performLockRequest2['target-network'] = 'network1'; + performLockRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; + performLockRequest2['timeout-duration'] = '3600'; + performLockRequest2['locker'] = 'alice'; + performLockRequest2['recipient'] = 'bob'; + performLockRequest2['param'] = 'bond01:a03'; // Locker and Recipient - const locker = performLockRequest['locker']; - const recipient = performLockRequest['recipient']; - let hashFn = performLockRequest['hash_fn']; - let hashBase64 = performLockRequest['hashBase64']; + const locker = performLockRequest2['locker']; + const recipient = performLockRequest2['recipient']; + let hashFn = performLockRequest2['hash_fn']; + let hashBase64 = performLockRequest2['hashBase64']; // Hash let hash: HashFunctions.Hash @@ -57,22 +55,22 @@ async function performLockHelper( // Timeout var timeout = 0, timeout2 = 0; const currTime = Math.floor(Date.now() / 1000); - if (performLockRequest['timeout-epoch']) { - let duration = performLockRequest['timeout-epoch'] - currTime - timeout = performLockRequest['timeout-epoch'] - timeout2 = performLockRequest['timeout-epoch'] + duration + if (performLockRequest2['timeout-epoch']) { + let duration = performLockRequest2['timeout-epoch'] - currTime + timeout = performLockRequest2['timeout-epoch'] + timeout2 = performLockRequest2['timeout-epoch'] + duration } - else if (performLockRequest['timeout-duration']) { - timeout = currTime + performLockRequest['timeout-duration'] - timeout2 = currTime + 2 * performLockRequest['timeout-duration'] + else if (performLockRequest2['timeout-duration']) { + timeout = currTime + performLockRequest2['timeout-duration'] + timeout2 = currTime + 2 * performLockRequest2['timeout-duration'] } - const params = performLockRequest['param'].split(':') + const params = performLockRequest2['param'].split(':') + const netConfig = getNetworkConfig(performLockRequest2['target-network']) - const netConfig = getNetworkConfig(performLockRequest['target-network']) if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { console.error( - `Please use a valid --target-network. No valid environment found for ${performLockRequest['target-network']} ` + `Please use a valid --target-network. No valid environment found for ${performLockRequest2['target-network']} ` ) return } @@ -81,12 +79,14 @@ async function performLockHelper( channel: netConfig.channelName, contractName: netConfig.chaincode, connProfilePath: netConfig.connProfilePath, - networkName: performLockRequest['target-network'], + networkName: performLockRequest2['target-network'], mspId: netConfig.mspId, userString: locker }) + logger.info(`network details: ${network}`); const lockerId = await network.wallet.get(locker) + const lockerCert = Buffer.from((lockerId).credentials.certificate).toString('base64') const recipientId = await network.wallet.get(recipient) @@ -94,7 +94,7 @@ async function performLockHelper( var funcToCall, asset - if (performLockRequest['fungible']) { + if (performLockRequest2['fungible']) { funcToCall = AssetManager.createFungibleHTLC asset = 'Fungible Asset' } else { @@ -106,89 +106,69 @@ async function performLockHelper( try { console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) - const res = await funcToCall(network.contract, - params[0], - params[1], - recipientCert, - hash, - timeout, - null) - if (!res.result) { - throw new Error() - } - console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) + // const res = await funcToCall(network.contract, + // params[0], + // params[1], + // recipientCert, + // hash, + // timeout, + // null) + // if (!res.result) { + // throw new Error() + // } + // console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) console.info('Asset Exchange: Lock Complete.') + } catch (error) { - console.error(`Could not Lock ${asset} in ${performLockRequest['target-network']}`) + console.error(`Could not Lock ${asset} in ${performLockRequest2['target-network']}`) } - // await new Promise(f => setTimeout(f, performLockRequest['timeout-duration'] * 1000 + 3000)); + // await new Promise(f => setTimeout(f, performLockRequest2['timeout-duration'] * 1000 + 3000)); await network.gateway.disconnect() - console.log('Gateways disconnected.') - - - // const viewPayload: state_pb.ViewPayload = performLockRequest.getViewPayload(); - // const ctx: eventsPb.ContractTransaction = writeExternalStateMessage.getCtx(); - // const keyCert = await getDriverKeyCert(); - - // const requestId: string = viewPayload.getRequestId(); - // if (!viewPayload.getError()) { - - // let interopArgIndices = [], viewsSerializedBase64 = [], addresses = [], viewContentsBase64 = []; - // const view: state_pb.View = viewPayload.getView(); - - // const result = InteroperableHelper.getResponseDataFromView(view, keyCert.key.toBytes()); - // if (result.contents) { - // viewContentsBase64.push(result.contents); - // } else { - // viewContentsBase64.push([]); - // } - - // interopArgIndices.push(ctx.getReplaceArgIndex()); - // addresses.push(result.viewAddress); - // viewsSerializedBase64.push(Buffer.from(viewPayload.getView().serializeBinary()).toString("base64")); - - // let ccArgsB64 = ctx.getArgsList(); - // let ccArgsStr = []; - // for (const ccArgB64 of ccArgsB64) { - // ccArgsStr.push(Buffer.from(ccArgB64).toString('utf8')); - // } - - // let gateway: Gateway = await getNetworkGateway(networkName); - // const network: Network = await gateway.getNetwork(ctx.getLedgerId()); - // const interopContract: Contract = network.getContract(process.env.INTEROP_CHAINCODE ? process.env.INTEROP_CHAINCODE : 'interop'); - - // const endorsingOrgs = ctx.getMembersList(); - // const invokeObject = { - // channel: ctx.getLedgerId(), - // ccFunc: ctx.getFunc(), - // ccArgs: ccArgsStr, - // contractName: ctx.getContractId() - // } - // logger.info(`writing external state to contract: ${ctx.getContractId()} with function: ${ctx.getFunc()}, and args: ${invokeObject.ccArgs} on channel: ${ctx.getLedgerId()}`); - - // const [ response, responseError ] = await handlePromise(InteroperableHelper.submitTransactionWithRemoteViews( - // interopContract, - // invokeObject, - // interopArgIndices, - // addresses, - // viewsSerializedBase64, - // viewContentsBase64, - // endorsingOrgs - // )); - // if (responseError) { - // logger.error(`Failed writing to the ledger with error: ${responseError}`); - // gateway.disconnect(); - // throw responseError; - // } - // logger.debug(`write successful`); - // gateway.disconnect(); - // } else { - // const errorString: string = `erroneous viewPayload identified in WriteExternalState processing`; - // logger.error(`error viewPayload.getError(): ${JSON.stringify(viewPayload.getError())}`); - // throw new Error(errorString); - // } + logger.info('Gateways disconnected.') + + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(performLockRequest.getSessionId()); + request.setStatus("Locked"); + client.sendAssetStatus(request, relayCallback); +} + +function getRelayClientForAssetStatusResponse() { + let client: satp_grpc_pb.SATPClient; + if (process.env.RELAY_TLS === 'true') { + if (!process.env.RELAY_TLSCA_CERT_PATH || process.env.RELAY_TLSCA_CERT_PATH == "") { + client = new satp_grpc_pb.SATPClient( + process.env.RELAY_ENDPOINT, + credentials.createSsl() + ); + } else { + if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { + throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); + } + const rootCert = fs.readFileSync(process.env.RELAY_TLSCA_CERT_PATH); + client = new satp_grpc_pb.SATPClient( + process.env.RELAY_ENDPOINT, + credentials.createSsl(rootCert) + ); + } + } else { + client = new satp_grpc_pb.SATPClient( + process.env.RELAY_ENDPOINT, + credentials.createInsecure() + ); + } + return client; +} + +// handle callback +function relayCallback(err: any, response: any) { + if (response) { + logger.info(`Relay Callback Response: ${JSON.stringify(response.toObject())}`); + } else if (err) { + logger.error(`Relay Callback Error: ${err}`); + } } export { From 92fb3d37137bf1b7d77a89a8c14ddf33fe07e606 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 29 Aug 2023 08:54:03 +0100 Subject: [PATCH 36/59] initial commit --- .../core/drivers/fabric-driver/server/satp.ts | 30 +-- weaver/core/relay/Cargo.lock | 66 ++++- weaver/core/relay/Cargo.toml | 1 + weaver/core/relay/src/services/helpers.rs | 232 ++++++++++++------ .../core/relay/src/services/satp_service.rs | 27 ++ 5 files changed, 259 insertions(+), 97 deletions(-) diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index cbea82e1cb..9509ba59de 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -26,10 +26,10 @@ async function performLockHelper( let performLockRequest2 = {}; performLockRequest2['target-network'] = 'network1'; performLockRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; - performLockRequest2['timeout-duration'] = '3600'; + performLockRequest2['timeout-duration'] = parseInt('3600'); performLockRequest2['locker'] = 'alice'; performLockRequest2['recipient'] = 'bob'; - performLockRequest2['param'] = 'bond01:a03'; + performLockRequest2['param'] = 'bond01:a05'; // Locker and Recipient const locker = performLockRequest2['locker']; @@ -84,11 +84,8 @@ async function performLockHelper( userString: locker }) - logger.info(`network details: ${network}`); const lockerId = await network.wallet.get(locker) - const lockerCert = Buffer.from((lockerId).credentials.certificate).toString('base64') - const recipientId = await network.wallet.get(recipient) const recipientCert = Buffer.from((recipientId).credentials.certificate).toString('base64') @@ -103,20 +100,19 @@ async function performLockHelper( } console.info(`Asset Exchange: Lock ${asset}:\n`); - try { console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) - // const res = await funcToCall(network.contract, - // params[0], - // params[1], - // recipientCert, - // hash, - // timeout, - // null) - // if (!res.result) { - // throw new Error() - // } - // console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) + const res = await funcToCall(network.contract, + params[0], + params[1], + recipientCert, + hash, + timeout, + null) + if (!res.result) { + throw new Error() + } + console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) console.info('Asset Exchange: Lock Complete.') } catch (error) { diff --git a/weaver/core/relay/Cargo.lock b/weaver/core/relay/Cargo.lock index 1d5b2e3080..ed534ff613 100644 --- a/weaver/core/relay/Cargo.lock +++ b/weaver/core/relay/Cargo.lock @@ -85,7 +85,7 @@ checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes", "futures-util", "http", @@ -170,6 +170,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "bumpalo" version = "3.13.0" @@ -209,6 +215,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "colored" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +dependencies = [ + "is-terminal", + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "config" version = "0.11.0" @@ -644,6 +661,17 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix 0.38.9", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -681,7 +709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ "arrayvec", - "bitflags", + "bitflags 1.3.2", "cfg-if", "ryu", "static_assertions", @@ -705,6 +733,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" + [[package]] name = "listenfd" version = "1.0.1" @@ -863,7 +897,7 @@ version = "0.10.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "foreign-types", "libc", @@ -1104,7 +1138,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1113,7 +1147,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1140,6 +1174,7 @@ dependencies = [ "base64 0.20.0", "bincode", "cacti_weaver_protos_rs", + "colored", "config", "futures", "listenfd", @@ -1223,11 +1258,24 @@ version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.5", "windows-sys 0.48.0", ] @@ -1295,7 +1343,7 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -1464,7 +1512,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix", + "rustix 0.37.20", "windows-sys 0.48.0", ] diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index 123e42eec4..43fa28f188 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -39,6 +39,7 @@ reqwest = { version = "0.11.16", features = ["json"] } serde_json = "1.0.95" # cacti_weaver_protos_rs = "2.0.0-alpha.1" cacti_weaver_protos_rs = { path = "../../common/protos-rs/pkg" } +colored = {version="2.0.4"} [build-dependencies] tonic-build = "0.8.4" diff --git a/weaver/core/relay/src/services/helpers.rs b/weaver/core/relay/src/services/helpers.rs index 606edcad65..2c8b5e6194 100644 --- a/weaver/core/relay/src/services/helpers.rs +++ b/weaver/core/relay/src/services/helpers.rs @@ -5,17 +5,15 @@ use weaverpb::common::ack::{ack}; use weaverpb::common::query::Query; use weaverpb::common::state::{request_state, RequestState}; -use weaverpb::common::events::{event_subscription_state, EventSubscriptionState}; -use weaverpb::common::events::{EventSubscription, EventStates, EventState, EventPublication}; use weaverpb::driver::driver::driver_communication_client::DriverCommunicationClient; use crate::db::Database; -use crate::services::types::{Driver, Network}; use crate::error::Error; +use crate::services::types::{Driver, Network}; use config; -use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use std::fs; +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; // Locally scoped function to update request status in db. This function is // called for the first time after an Ack is received from the remote relay. @@ -30,11 +28,20 @@ pub fn update_event_subscription_status( db_open_retry_backoff_msec: u32, message: String, ) { - let driver_error_constants = fs::read_to_string("./driver/driver-error-constants.json").expect("Unable to read file: ./driver/driver-error-constants.json"); + let driver_error_constants = fs::read_to_string("./driver/driver-error-constants.json") + .expect("Unable to read file: ./driver/driver-error-constants.json"); let driver_error_constants_json: serde_json::Value = serde_json::from_str(&driver_error_constants).expect("JSON was not well-formatted"); - let driver_sub_exists_error = driver_error_constants_json.get("SUB_EXISTS").unwrap().as_str().unwrap(); - let driver_sub_exists_error_without_args = *(driver_sub_exists_error.split("{0}").collect::>().first().unwrap()); + let driver_sub_exists_error = driver_error_constants_json + .get("SUB_EXISTS") + .unwrap() + .as_str() + .unwrap(); + let driver_sub_exists_error_without_args = *(driver_sub_exists_error + .split("{0}") + .collect::>() + .first() + .unwrap()); let db = Database { db_path: curr_db_path, @@ -53,42 +60,52 @@ pub fn update_event_subscription_status( target = EventSubscriptionState { status: event_subscription_state::Status::UnsubscribePending as i32, request_id: curr_request_id.clone(), - publishing_request_id: fetched_event_sub_state.publishing_request_id.to_string(), + publishing_request_id: fetched_event_sub_state + .publishing_request_id + .to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher, - event_publication_specs: fetched_event_sub_state.event_publication_specs + event_publication_specs: fetched_event_sub_state + .event_publication_specs, }; - }, + } event_subscription_state::Status::UnsubscribePending => { target = EventSubscriptionState { status: event_subscription_state::Status::Unsubscribed as i32, request_id: curr_request_id.clone(), - publishing_request_id: fetched_event_sub_state.publishing_request_id.to_string(), + publishing_request_id: fetched_event_sub_state + .publishing_request_id + .to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher, - event_publication_specs: fetched_event_sub_state.event_publication_specs + event_publication_specs: fetched_event_sub_state + .event_publication_specs, }; - }, - event_subscription_state::Status::SubscribePendingAck => { + } + event_subscription_state::Status::SubscribePendingAck => { target = EventSubscriptionState { status: event_subscription_state::Status::SubscribePending as i32, request_id: curr_request_id.clone(), publishing_request_id: "".to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, - event_subscription_state::Status::SubscribePending => { + } + event_subscription_state::Status::SubscribePending => { target = EventSubscriptionState { status: event_subscription_state::Status::Subscribed as i32, request_id: curr_request_id.clone(), publishing_request_id: curr_request_id.clone(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, + } _ => { target = EventSubscriptionState { status: event_subscription_state::Status::Error as i32, @@ -96,9 +113,11 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: "Status is not supported or is invalid".to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, + } }, None => { target = EventSubscriptionState { @@ -107,41 +126,61 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: "No event subscription status set in database".to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, + } } } else { match message.find(driver_sub_exists_error_without_args) { Some(_index) => { - let old_request_id = *(message.split(driver_sub_exists_error_without_args).collect::>().last().unwrap()); + let old_request_id = *(message + .split(driver_sub_exists_error_without_args) + .collect::>() + .last() + .unwrap()); println!("Adding event publication spec to existing EventSubscriptionState. Extracted request id from message: {}", old_request_id.to_string()); - let old_event_sub_key = get_event_subscription_key(old_request_id.to_string()); - let mut existing_event_sub_state = db.get::(old_event_sub_key.to_string()) - .expect(&format!("No EventSubscriptionState found in DB for request_id provided {}", old_request_id.to_string())); - - let new_event_pub_spec = fetched_event_sub_state.event_publication_specs.first().unwrap(); + let old_event_sub_key = + get_event_subscription_key(old_request_id.to_string()); + let mut existing_event_sub_state = db + .get::(old_event_sub_key.to_string()) + .expect(&format!( + "No EventSubscriptionState found in DB for request_id provided {}", + old_request_id.to_string() + )); + + let new_event_pub_spec = fetched_event_sub_state + .event_publication_specs + .first() + .unwrap(); let mut unique_pub_spec_flag = true; - for event_pub_spec in existing_event_sub_state.event_publication_specs.iter() { + for event_pub_spec in + existing_event_sub_state.event_publication_specs.iter() + { if *new_event_pub_spec == *event_pub_spec { unique_pub_spec_flag = false; break; } } if unique_pub_spec_flag { - existing_event_sub_state.event_publication_specs.push((*new_event_pub_spec).clone()); + existing_event_sub_state + .event_publication_specs + .push((*new_event_pub_spec).clone()); let updated_event_sub_state = EventSubscriptionState { status: event_subscription_state::Status::Subscribed as i32, request_id: old_request_id.to_string(), publishing_request_id: old_request_id.to_string(), message: existing_event_sub_state.message.to_string(), event_matcher: existing_event_sub_state.event_matcher.clone(), - event_publication_specs: existing_event_sub_state.event_publication_specs.clone(), + event_publication_specs: existing_event_sub_state + .event_publication_specs + .clone(), }; db.set(&old_event_sub_key.to_string(), &updated_event_sub_state) .expect("Failed to insert into DB"); - + target = EventSubscriptionState { status: event_subscription_state::Status::DuplicateQuerySubscribed as i32, request_id: curr_request_id.clone(), @@ -157,10 +196,12 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), } }; - }, + } None => { target = EventSubscriptionState { status: event_subscription_state::Status::Error as i32, @@ -168,28 +209,31 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; } } } - + // Panic if this fails, atm the panic is just logged by the tokio runtime db.set(&event_sub_key.to_string(), &target) .expect("Failed to insert into DB"); println!("Successfully written EventSubscriptionState to database"); - println!("{:?}\n", db.get::(event_sub_key.to_string()).unwrap()) - }, + println!( + "{:?}\n", + db.get::(event_sub_key.to_string()) + .unwrap() + ) + } Err(e) => { println!("EventSubscription Request not found. Error: {:?}", e); - }, + } } } -pub fn get_driver( - network_id: String, - conf: config::Config, -) -> Result { +pub fn get_driver(network_id: String, conf: config::Config) -> Result { // get the driver type from the networks map let networks_table = conf .get_table("networks") @@ -239,7 +283,8 @@ pub async fn get_driver_client( .ca_certificate(ca) .domain_name(hostname); - let channel = Channel::from_shared(driver_address).unwrap() + let channel = Channel::from_shared(driver_address) + .unwrap() .tls_config(tls)? .connect() .await @@ -249,10 +294,9 @@ pub async fn get_driver_client( } else { client = DriverCommunicationClient::connect(driver_address).await?; } - return Ok(client) + return Ok(client); } - pub async fn driver_sign_subscription_helper( event_subscription: EventSubscription, request_id: String, @@ -263,7 +307,10 @@ pub async fn driver_sign_subscription_helper( match result { Ok(driver_info) => { let client = get_driver_client(driver_info).await?; - println!("Sending Sign EventSubscription Request to driver: {:?}", event_subscription.clone()); + println!( + "Sending Sign EventSubscription Request to driver: {:?}", + event_subscription.clone() + ); let signed_query = client .clone() .request_signed_event_subscription_query(event_subscription) @@ -271,10 +318,13 @@ pub async fn driver_sign_subscription_helper( .into_inner(); if signed_query.clone().request_id.to_string() == request_id.to_string() { println!("Signed Query Response from driver={:?}\n", signed_query); - return Ok(signed_query) + return Ok(signed_query); } - Err(Error::Simple(format!("Error while requesting signature from driver: {:?}", signed_query))) - }, + Err(Error::Simple(format!( + "Error while requesting signature from driver: {:?}", + signed_query + ))) + } Err(e) => Err(e), } } @@ -311,8 +361,7 @@ pub fn update_event_state( message: message.to_string(), }; updated_event_states.push(new_event_state); - } - else { + } else { updated_event_states.push(fetched_event_state); } } @@ -320,17 +369,18 @@ pub fn update_event_state( db.set(&event_publish_key.to_string(), &updated_event_states) .expect("Failed to insert into DB"); println!("Successfully updated EventStates in database"); - }, + } Err(e) => { println!("EventStates not found. Error: {:?}", e); - }, + } } } pub fn try_mark_request_state_deleted(state: RequestState, request_id: String, db: Database) { let state_status = request_state::Status::from_i32(state.clone().status).expect("No Status"); - if state_status == request_state::Status::Error || - state_status == request_state::Status::Completed { + if state_status == request_state::Status::Error + || state_status == request_state::Status::Completed + { let deleted_request_state = RequestState { status: request_state::Status::Deleted as i32, request_id: request_id.to_string(), @@ -341,7 +391,12 @@ pub fn try_mark_request_state_deleted(state: RequestState, request_id: String, d } } -pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: String, event_publish_key: String, db: Database) { +pub fn mark_event_states_deleted( + fetched_event_states: EventStates, + request_id: String, + event_publish_key: String, + db: Database, +) { let mut updated_event_states: Vec = Vec::new(); for fetched_event_state in fetched_event_states.states { let deleted_request_state = RequestState { @@ -356,7 +411,7 @@ pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: }; updated_event_states.push(deleted_event_state); } - + db.set(&event_publish_key.to_string(), &updated_event_states) .expect("EventState Delete: Failed to insert into DB"); } @@ -381,11 +436,15 @@ pub fn delete_event_pub_spec( db_open_retry_backoff_msec: db_open_retry_backoff_msec, }; let mut event_sub_key = get_event_subscription_key(request_id.to_string()); - let mut event_sub_state = db.get::(event_sub_key.to_string()) - .expect(&format!("No EventSubscriptionState found in DB for request_id provided {}", request_id.to_string())); - + let mut event_sub_state = db + .get::(event_sub_key.to_string()) + .expect(&format!( + "No EventSubscriptionState found in DB for request_id provided {}", + request_id.to_string() + )); + let mut del_event_pub_spec = event_pub_spec; - + if event_sub_state.status == event_subscription_state::Status::DuplicateQuerySubscribed as i32 { let updated_state = EventSubscriptionState { status: event_subscription_state::Status::Unsubscribed as i32, @@ -393,18 +452,30 @@ pub fn delete_event_pub_spec( publishing_request_id: event_sub_state.publishing_request_id.to_string(), message: "Unsubscription successful".to_string(), event_matcher: event_sub_state.event_matcher, - event_publication_specs: event_sub_state.event_publication_specs + event_publication_specs: event_sub_state.event_publication_specs, }; db.set(&event_sub_key.to_string(), &updated_state) .expect("Failed to insert into DB"); - del_event_pub_spec = updated_state.clone().event_publication_specs.first().unwrap().clone(); - println!("Removed EventSubscriptionState from database: {:?}", updated_state); + del_event_pub_spec = updated_state + .clone() + .event_publication_specs + .first() + .unwrap() + .clone(); + println!( + "Removed EventSubscriptionState from database: {:?}", + updated_state + ); event_sub_key = get_event_subscription_key(updated_state.publishing_request_id.to_string()); - event_sub_state = db.get::(event_sub_key.to_string()) - .expect(&format!("No EventSubscriptionState found in DB for request_id provided {}", updated_state.publishing_request_id.to_string())); + event_sub_state = db + .get::(event_sub_key.to_string()) + .expect(&format!( + "No EventSubscriptionState found in DB for request_id provided {}", + updated_state.publishing_request_id.to_string() + )); } - + let mut flag = true; for (i, curr_event_pub_spec) in event_sub_state.event_publication_specs.iter().enumerate() { if *curr_event_pub_spec == del_event_pub_spec { @@ -422,13 +493,32 @@ pub fn delete_event_pub_spec( db.set(&event_sub_key.to_string(), &event_sub_state) .expect("Failed to insert into DB"); println!("Successfully deleted Event Publication from existing EventSubscriptionState from DB"); - + return 0; } pub fn get_event_subscription_key(request_id: String) -> String { return format!("event_sub_{}", request_id); } + pub fn get_event_publication_key(request_id: String) -> String { return format!("event_pub_{}", request_id); -} \ No newline at end of file +} + +pub fn println_stage_heading(stage_id: String) { + println!( + "{} {} {}", + "\n --------- Stage".yellow().bold(), + stage_id.yellow().bold(), + "started --------- \n".yellow().bold() + ); +} + +pub fn println_step_heading(step_id: String) { + println!( + "{} {} {}", + "\n --------- Step".bright_cyan().bold(), + step_id.bright_cyan().bold(), + " --------- \n".bright_cyan().bold() + ); +} diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index b9bf229eb9..14e970b4a5 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -12,6 +12,7 @@ use weaverpb::relay::satp::{ // Internal modules use crate::error::Error; use crate::relay_proto::parse_address; +use crate::services::helpers::{println_stage_heading, println_step_heading}; use crate::services::satp_helper::{ create_ack_error_message, create_perform_lock_request, get_request_id_from_transfer_proposal_receipt, log_request_in_local_satp_db, @@ -55,6 +56,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_stage_heading("1".to_string()); + println_step_heading("1.1".to_string()); println!( "Got a TransferProposalClaimsRequest from {:?} - {:?}", request.remote_addr(), @@ -108,6 +111,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("1.2".to_string()); println!( "Got an ack transfer proposal receipt request from {:?} - {:?}", request.remote_addr(), @@ -169,6 +173,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("1.3".to_string()); println!( "Got a TransferCommenceRequest from {:?} - {:?}", request.remote_addr(), @@ -214,6 +219,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("1.4".to_string()); println!( "Got an ack commence request from {:?} - {:?}", request.remote_addr(), @@ -312,6 +318,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("2.2".to_string()); println!( "Got a LockAssertionRequest from {:?} - {:?}", request.remote_addr(), @@ -354,6 +361,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("2.4".to_string()); println!( "Got an lock assertion receipt request from {:?} - {:?}", request.remote_addr(), @@ -408,6 +416,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("3.1".to_string()); println!( "Got commit prepare request from {:?} - {:?}", request.remote_addr(), @@ -456,6 +465,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("3.3".to_string()); println!( "Got commit ready request from {:?} - {:?}", request.remote_addr(), @@ -503,6 +513,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("3.5".to_string()); println!( "Got commit final assertion request from {:?} - {:?}", request.remote_addr(), @@ -557,6 +568,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("3.7".to_string()); println!( "Got commit final assertion request from {:?} - {:?}", request.remote_addr(), @@ -608,6 +620,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("3.9".to_string()); println!( "Got commit final assertion request from {:?} - {:?}", request.remote_addr(), @@ -813,23 +826,27 @@ pub fn process_send_asset_status_request( let status = send_asset_status_request.status.as_str(); match status { "Locked" => { + println_step_heading("2.1B".to_string()); println!("Received asset status as Locked. Sending the lock assertion request"); let lock_assertion_request = create_lock_assertion_request(send_asset_status_request); result = send_lock_assertion_request(lock_assertion_request, conf) } "Created" => { + println_step_heading("3.2B".to_string()); println!("Received asset status as Created. Sending the commit ready request"); let commit_ready_request = create_commit_ready_request(send_asset_status_request); result = send_commit_ready_request(commit_ready_request, conf); } "Extinguished" => { + println_step_heading("3.4B".to_string()); println!("Received asset status as Extinguished. Sending the commit final assertion request"); let commit_final_assertion_request = create_commit_final_assertion_request(send_asset_status_request); result = send_commit_final_assertion_request(commit_final_assertion_request, conf) } "Finalized" => { + println_step_heading("3.6B".to_string()); println!( "Received asset status as Finalized. Sending the ack final receipt request" ); @@ -1184,6 +1201,8 @@ fn send_lock_assertion_broadcast_request( lock_assertion_request: LockAssertionRequest, conf: config::Config, ) -> Result { + println_step_heading("2.3".to_string()); + let request_id = &lock_assertion_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); let (use_tls, tlsca_cert_path) = @@ -1209,6 +1228,9 @@ fn send_perform_lock_request( perform_lock_request: PerformLockRequest, conf: config::Config, ) -> Result { + println_stage_heading("2".to_string()); + println_step_heading("2.1A".to_string()); + let request_id = &perform_lock_request.session_id.to_string(); let driver_address = get_driver_address_from_perform_lock(perform_lock_request.clone()); let parsed_address = parse_address(driver_address)?; @@ -1240,6 +1262,7 @@ fn send_commit_prepare_request( commit_prepare_request: CommitPrepareRequest, conf: config::Config, ) -> Result { + println_stage_heading("3".to_string()); let request_id = &commit_prepare_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); let (use_tls, tlsca_cert_path) = @@ -1293,6 +1316,7 @@ fn send_create_asset_request( conf: config::Config, ) -> Result { // TODO + println_step_heading("3.2A".to_string()); let request_id = &commit_prepare_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); let (use_tls, tlsca_cert_path) = @@ -1320,6 +1344,7 @@ fn send_extinguish_request( conf: config::Config, ) -> Result { // TODO + println_step_heading("3.4A".to_string()); let request_id = &commit_ready_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_commit_ready(commit_ready_request.clone()); let (use_tls, tlsca_cert_path) = @@ -1375,6 +1400,7 @@ fn send_ack_final_receipt_request( conf: config::Config, ) -> Result { // TODO + println_step_heading("3.8".to_string()); let request_id = &ack_final_receipt_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); @@ -1403,6 +1429,7 @@ fn send_assign_asset_request( conf: config::Config, ) -> Result { // TODO + println_step_heading("3.6A".to_string()); let request_id = &commit_final_assertion_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_commit_final_assertion(commit_final_assertion_request.clone()); From 2dfb32176be251d369016124f2f5368ded4cbb1f Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Thu, 31 Aug 2023 08:38:47 +0100 Subject: [PATCH 37/59] Initial commit for create-asset, extinguish, and assign-asset --- .../pkg/src/generated/driver.driver.rs | 242 +++++++++++++++++- weaver/common/protos/driver/driver.proto | 26 +- .../core/drivers/fabric-driver/server/satp.ts | 66 ++++- .../drivers/fabric-driver/server/server.ts | 68 ++++- weaver/core/relay/src/services/satp_helper.rs | 211 ++++++++++++--- .../core/relay/src/services/satp_service.rs | 171 ++++++++----- 6 files changed, 656 insertions(+), 128 deletions(-) diff --git a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs index efa1273e38..a9b21a94f1 100644 --- a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs +++ b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs @@ -19,6 +19,27 @@ pub struct PerformLockRequest { #[prost(string, tag = "1")] pub session_id: ::prost::alloc::string::String, } +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateAssetRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExtinguishRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AssignAssetRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} /// Generated client implementations. pub mod driver_communication_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] @@ -190,7 +211,7 @@ pub mod driver_communication_client { ); self.inner.unary(request.into_request(), path, codec).await } - /// As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + /// As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver /// to lock a specific asset pub async fn perform_lock( &mut self, @@ -214,6 +235,78 @@ pub mod driver_communication_client { ); self.inner.unary(request.into_request(), path, codec).await } + /// As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + /// to create a specific asset + pub async fn create_asset( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/CreateAsset", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + /// to extinguish a specific asset + pub async fn extinguish( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/Extinguish", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + /// to assign a specific asset + pub async fn assign_asset( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/AssignAsset", + ); + self.inner.unary(request.into_request(), path, codec).await + } } } /// Generated server implementations. @@ -265,7 +358,7 @@ pub mod driver_communication_server { tonic::Response, tonic::Status, >; - /// As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + /// As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver /// to lock a specific asset async fn perform_lock( &self, @@ -274,6 +367,33 @@ pub mod driver_communication_server { tonic::Response, tonic::Status, >; + /// As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + /// to create a specific asset + async fn create_asset( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + /// to extinguish a specific asset + async fn extinguish( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + /// to assign a specific asset + async fn assign_asset( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct DriverCommunicationServer { @@ -549,6 +669,124 @@ pub mod driver_communication_server { }; Box::pin(fut) } + "/driver.driver.DriverCommunication/CreateAsset" => { + #[allow(non_camel_case_types)] + struct CreateAssetSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for CreateAssetSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).create_asset(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CreateAssetSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/driver.driver.DriverCommunication/Extinguish" => { + #[allow(non_camel_case_types)] + struct ExtinguishSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for ExtinguishSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).extinguish(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = ExtinguishSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/driver.driver.DriverCommunication/AssignAsset" => { + #[allow(non_camel_case_types)] + struct AssignAssetSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for AssignAssetSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).assign_asset(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = AssignAssetSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( diff --git a/weaver/common/protos/driver/driver.proto b/weaver/common/protos/driver/driver.proto index 6f0c0ccce0..b0681f8e4f 100644 --- a/weaver/common/protos/driver/driver.proto +++ b/weaver/common/protos/driver/driver.proto @@ -24,6 +24,18 @@ message PerformLockRequest { string session_id = 1; } +message CreateAssetRequest { + string session_id = 1; +} + +message ExtinguishRequest { + string session_id = 1; +} + +message AssignAssetRequest { + string session_id = 1; +} + service DriverCommunication { // Data Sharing // the remote relay sends a RequestDriverState request to its driver with a @@ -43,7 +55,19 @@ service DriverCommunication { // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger rpc WriteExternalState(WriteExternalStateMessage) returns (common.ack.Ack) {} - // As part of SATP, the src-reply (sending gateway) sends a PerformLock request to its driver + // As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver // to lock a specific asset rpc PerformLock(PerformLockRequest) returns (common.ack.Ack) {} + + // As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + // to create a specific asset + rpc CreateAsset(CreateAssetRequest) returns (common.ack.Ack) {} + + // As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + // to extinguish a specific asset + rpc Extinguish(ExtinguishRequest) returns (common.ack.Ack) {} + + // As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + // to assign a specific asset + rpc AssignAsset(AssignAssetRequest) returns (common.ack.Ack) {} } \ No newline at end of file diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index 9509ba59de..fea151a0c3 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -102,17 +102,17 @@ async function performLockHelper( console.info(`Asset Exchange: Lock ${asset}:\n`); try { console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) - const res = await funcToCall(network.contract, - params[0], - params[1], - recipientCert, - hash, - timeout, - null) - if (!res.result) { - throw new Error() - } - console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) + // const res = await funcToCall(network.contract, + // params[0], + // params[1], + // recipientCert, + // hash, + // timeout, + // null) + // if (!res.result) { + // throw new Error() + // } + // console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) console.info('Asset Exchange: Lock Complete.') } catch (error) { @@ -131,6 +131,45 @@ async function performLockHelper( client.sendAssetStatus(request, relayCallback); } +async function createAssetHelper( + createAssetRequest: driverPb.CreateAssetRequest, + networkName: string +): Promise { + + // TODO + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(createAssetRequest.getSessionId()); + request.setStatus("Created"); + client.sendAssetStatus(request, relayCallback); +} + +async function extinguishHelper( + extinguishRequest: driverPb.ExtinguishRequest, + networkName: string +): Promise { + + // TODO + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(extinguishRequest.getSessionId()); + request.setStatus("Extinguished"); + client.sendAssetStatus(request, relayCallback); +} + +async function assignAssetHelper( + assignAssetRequest: driverPb.AssignAssetRequest, + networkName: string +): Promise { + + // TODO + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(assignAssetRequest.getSessionId()); + request.setStatus("Finalized"); + client.sendAssetStatus(request, relayCallback); +} + function getRelayClientForAssetStatusResponse() { let client: satp_grpc_pb.SATPClient; if (process.env.RELAY_TLS === 'true') { @@ -168,5 +207,8 @@ function relayCallback(err: any, response: any) { } export { - performLockHelper + performLockHelper, + createAssetHelper, + extinguishHelper, + assignAssetHelper } diff --git a/weaver/core/drivers/fabric-driver/server/server.ts b/weaver/core/drivers/fabric-driver/server/server.ts index d31c7805ff..427307e149 100644 --- a/weaver/core/drivers/fabric-driver/server/server.ts +++ b/weaver/core/drivers/fabric-driver/server/server.ts @@ -19,7 +19,7 @@ import 'dotenv/config'; import { loadEventSubscriptionsFromStorage, monitorBlockForMissedEvents } from './listener' import { walletSetup } from './walletSetup'; import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery, writeExternalStateHelper } from "./events" -import { performLockHelper } from "./satp" +import { performLockHelper, createAssetHelper, extinguishHelper, assignAssetHelper } from "./satp" import * as path from 'path'; import { handlePromise, relayCallback, getRelayClientForQueryResponse, getRelayClientForEventSubscription, delay } from './utils'; import { dbConnectionTest, eventSubscriptionTest } from "./tests" @@ -240,7 +240,70 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { performLockHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { const ack_response = new ack_pb.Ack(); ack_response.setRequestId(requestId); - ack_response.setMessage('Successfully written to the ledger'); + ack_response.setMessage('Successfully locked the asset'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, + createAsset: (call: { request: driverPb.CreateAssetRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + createAssetHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully created the asset'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, + extinguish: (call: { request: driverPb.ExtinguishRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + extinguishHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully extinguished the asset'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, + assignAsset: (call: { request: driverPb.AssignAssetRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + assignAssetHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully assigned the asset'); ack_response.setStatus(ack_pb.Ack.STATUS.OK); // gRPC response. logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); @@ -255,6 +318,7 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { callback(null, ack_err_response); }); }, + }); // Prepares required crypto material for communication with the fabric network diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 9894ca8f69..61c13bf146 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -6,7 +6,9 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use tonic::Response; use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::state::{request_state, RequestState}; -use weaverpb::driver::driver::PerformLockRequest; +use weaverpb::driver::driver::{ + AssignAssetRequest, CreateAssetRequest, ExtinguishRequest, PerformLockRequest, +}; use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ @@ -277,24 +279,28 @@ pub fn spawn_send_commit_prepare_request( } pub fn spawn_send_create_asset_request( - commit_prepare_request: CommitPrepareRequest, - relay_host: String, - relay_port: String, - use_tls: bool, - tlsca_cert_path: String, - conf: Config, + driver_info: Driver, + create_asset_request: CreateAssetRequest, ) { tokio::spawn(async move { - let request_id = commit_prepare_request.session_id.to_string(); + let request_id = create_asset_request.session_id.to_string(); println!( - "Creating the asset corresponding to the commit prepare request {:?}", + "Creating the asset corresponding to the create asset request {:?}", request_id ); - // TODO - // Creating the asset in the target network - // Subscribe to the status event - // Once the message is broadcast, call the call_commit_ready endpoint - // log the results + + // TODO: pass the required info to lock the relevant asset + // Call the driver to lock the asset + let result = call_create_asset(driver_info, create_asset_request).await; + match result { + Ok(_) => { + println!("Create asset request sent to driver\n") + } + Err(e) => { + println!("Error sending create asset request to driver: {:?}\n", e); + // TODO: what to do in this case? + } + } }); } @@ -325,23 +331,28 @@ pub fn spawn_send_commit_ready_request( } pub fn spawn_send_assign_asset_request( - commit_final_assertion_request: CommitFinalAssertionRequest, - relay_host: String, - relay_port: String, - use_tls: bool, - tlsca_cert_path: String, - conf: Config, + driver_info: Driver, + assign_asset_request: AssignAssetRequest, ) { tokio::spawn(async move { - let request_id = commit_final_assertion_request.session_id.to_string(); + let request_id = assign_asset_request.session_id.to_string(); println!( - "Assigning the asset corresponding to the commit final assertion request {:?}", + "Assigning the asset corresponding to the assign asset request {:?}", request_id ); - // TODO - // Assigning the asset in the target network - // Once the asset is assigned, call the call_ack_final_receipt endpoint - // log the results + + // TODO: pass the required info to assign the relevant asset + // Call the driver to assign the asset + let result = call_assign_asset(driver_info, assign_asset_request).await; + match result { + Ok(_) => { + println!("Assign asset request sent to driver\n") + } + Err(e) => { + println!("Error sending assign asset request to driver: {:?}\n", e); + // TODO: what to do in this case? + } + } }); } @@ -408,24 +419,29 @@ pub fn spawn_send_ack_final_receipt_broadcast_request( }); } -pub fn spawn_send_extinguish_request( - commit_ready_request: CommitReadyRequest, - relay_host: String, - relay_port: String, - use_tls: bool, - tlsca_cert_path: String, - conf: Config, -) { +pub fn spawn_send_extinguish_request(driver_info: Driver, extinguish_request: ExtinguishRequest) { tokio::spawn(async move { - let request_id = commit_ready_request.session_id.to_string(); + let request_id = extinguish_request.session_id.to_string(); println!( - "Extinguishing the asset corresponding to the commit final assertion request {:?}", + "Extinguishing the asset corresponding to the extinguish request {:?}", request_id ); - // TODO - // Assigning the asset in the target network - // Once the asset is assigned, call the call_ack_final_receipt endpoint - // log the results + + // TODO: pass the required info to lock the relevant asset + // Call the driver to lock the asset + let result = call_extinguish(driver_info, extinguish_request).await; + match result { + Ok(_) => { + println!("Extinguishing asset request sent to driver\n") + } + Err(e) => { + println!( + "Error sending extinguishing asset request to driver: {:?}\n", + e + ); + // TODO: what to do in this case? + } + } }); } @@ -482,6 +498,78 @@ async fn call_perform_lock( } } +async fn call_create_asset( + driver_info: Driver, + create_asset_request: CreateAssetRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to create the asset"); + let ack = client + .clone() + .create_asset(create_asset_request) + .await? + .into_inner(); + println!("Response ACK from driver to create the asset {:?}\n", ack); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + +async fn call_extinguish( + driver_info: Driver, + extinguish_request: ExtinguishRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to extinguish the asset"); + let ack = client + .clone() + .extinguish(extinguish_request) + .await? + .into_inner(); + println!( + "Response ACK from driver to extinguish the asset {:?}\n", + ack + ); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + +async fn call_assign_asset( + driver_info: Driver, + assign_asset_request: AssignAssetRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to assign the asset"); + let ack = client + .clone() + .assign_asset(assign_asset_request) + .await? + .into_inner(); + println!("Response ACK from driver to assign the asset {:?}\n", ack); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + // Call the transfer_commence endpoint on the receiver gateway pub async fn call_transfer_commence( relay_host: String, @@ -946,6 +1034,34 @@ pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> return perform_lock_request; } +pub fn create_create_asset_request( + commit_prepare_request: CommitPrepareRequest, +) -> CreateAssetRequest { + // TODO: remove hard coded values + let create_asset_request = CreateAssetRequest { + session_id: "session_id1".to_string(), + }; + return create_asset_request; +} + +pub fn create_extinguish_request(commit_ready_request: CommitReadyRequest) -> ExtinguishRequest { + // TODO: remove hard coded values + let extinguish_request = ExtinguishRequest { + session_id: "session_id1".to_string(), + }; + return extinguish_request; +} + +pub fn create_assign_asset_request( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> AssignAssetRequest { + // TODO: remove hard coded values + let assign_asset_request = AssignAssetRequest { + session_id: "session_id1".to_string(), + }; + return assign_asset_request; +} + pub fn generate_commit_final_assertion_request( commit_ready_request: CommitReadyRequest, ) -> CommitFinalAssertionRequest { @@ -1171,6 +1287,21 @@ pub fn get_driver_address_from_perform_lock(perform_lock_request: PerformLockReq return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); } +pub fn get_driver_address_from_create_asset(create_asset_request: CreateAssetRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + +pub fn get_driver_address_from_extinguish(extinguish_request: ExtinguishRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + +pub fn get_driver_address_from_assign_asset(assign_asset_request: AssignAssetRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 14e970b4a5..e33e3610d9 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,6 +1,8 @@ // Internal generated modules use weaverpb::common::ack::{ack, Ack}; -use weaverpb::driver::driver::PerformLockRequest; +use weaverpb::driver::driver::{ + AssignAssetRequest, CreateAssetRequest, ExtinguishRequest, PerformLockRequest, +}; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{ AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, @@ -14,7 +16,8 @@ use crate::error::Error; use crate::relay_proto::parse_address; use crate::services::helpers::{println_stage_heading, println_step_heading}; use crate::services::satp_helper::{ - create_ack_error_message, create_perform_lock_request, + create_ack_error_message, create_assign_asset_request, create_create_asset_request, + create_extinguish_request, create_perform_lock_request, get_request_id_from_transfer_proposal_receipt, log_request_in_local_satp_db, log_request_in_remote_satp_db, }; @@ -26,10 +29,12 @@ use super::satp_helper::{ create_commit_final_assertion_request, create_commit_prepare_request, create_commit_ready_request, create_lock_assertion_request, create_transfer_commence_request, create_transfer_completed_request, create_transfer_proposal_receipt_request, - get_driver_address_from_perform_lock, get_relay_from_ack_commence, - get_relay_from_ack_final_receipt, get_relay_from_commit_final_assertion, - get_relay_from_commit_prepare, get_relay_from_commit_ready, get_relay_from_lock_assertion, - get_relay_from_transfer_commence, get_relay_from_transfer_proposal_receipt, get_relay_params, + get_driver_address_from_assign_asset, get_driver_address_from_create_asset, + get_driver_address_from_extinguish, get_driver_address_from_perform_lock, + get_relay_from_ack_commence, get_relay_from_ack_final_receipt, + get_relay_from_commit_final_assertion, get_relay_from_commit_prepare, + get_relay_from_commit_ready, get_relay_from_lock_assertion, get_relay_from_transfer_commence, + get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, spawn_send_ack_final_receipt_broadcast_request, spawn_send_ack_final_receipt_request, spawn_send_assign_asset_request, spawn_send_commit_final_assertion_request, @@ -785,7 +790,8 @@ pub fn process_ack_commence_request( // TODO some processing if is_valid_request { println!("The ack commence request is valid\n"); - let perform_lock_request = create_perform_lock_request(ack_commence_request); + let perform_lock_request: PerformLockRequest = + create_perform_lock_request(ack_commence_request); match send_perform_lock_request(perform_lock_request, conf) { Ok(ack) => { println!("Ack ack commence request."); @@ -963,7 +969,9 @@ pub fn process_commit_prepare_request( // TODO some processing if is_valid_request { println!("The commit prepare request is valid\n"); - match send_create_asset_request(commit_prepare_request, conf) { + let create_asset_request: CreateAssetRequest = + create_create_asset_request(commit_prepare_request); + match send_create_asset_request(create_asset_request, conf) { Ok(ack) => { println!("Ack commit prepare request."); let reply = Ok(ack); @@ -998,7 +1006,8 @@ pub fn process_commit_ready_request( // TODO some processing if is_valid_request { println!("The commit ready request is valid\n"); - match send_extinguish_request(commit_ready_request, conf) { + let extinguish_request: ExtinguishRequest = create_extinguish_request(commit_ready_request); + match send_extinguish_request(extinguish_request, conf) { Ok(ack) => { println!("Ack commit ready request."); let reply = Ok(ack); @@ -1034,7 +1043,9 @@ pub fn process_commit_final_assertion_request( // TODO some processing if is_valid_request { println!("The commit final assertion request is valid\n"); - match send_assign_asset_request(commit_final_assertion_request, conf) { + let assign_asset_request: AssignAssetRequest = + create_assign_asset_request(commit_final_assertion_request); + match send_assign_asset_request(assign_asset_request, conf) { Ok(ack) => { println!("Ack commit final assertion request."); let reply = Ok(ack); @@ -1312,59 +1323,72 @@ fn send_commit_ready_request( } fn send_create_asset_request( - commit_prepare_request: CommitPrepareRequest, + create_asset_request: CreateAssetRequest, conf: config::Config, ) -> Result { // TODO println_step_heading("3.2A".to_string()); - let request_id = &commit_prepare_request.session_id.to_string(); - let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); - let (use_tls, tlsca_cert_path) = - get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - spawn_send_create_asset_request( - commit_prepare_request, - relay_host, - relay_port, - use_tls, - tlsca_cert_path, - conf, - ); + let request_id = &create_asset_request.session_id.to_string(); + let driver_address = get_driver_address_from_create_asset(create_asset_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request_id.to_string(), - message: "Ack of the commit prepare request".to_string(), - }; - return Ok(reply); + match result { + Ok(driver_info) => { + spawn_send_create_asset_request(driver_info, create_asset_request); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the commit prepare request failed. Driver not found {:?}", + e + ), + }); + } + } } fn send_extinguish_request( - commit_ready_request: CommitReadyRequest, + extinguish_request: ExtinguishRequest, conf: config::Config, ) -> Result { // TODO println_step_heading("3.4A".to_string()); - let request_id = &commit_ready_request.session_id.to_string(); - let (relay_host, relay_port) = get_relay_from_commit_ready(commit_ready_request.clone()); - let (use_tls, tlsca_cert_path) = - get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - - spawn_send_extinguish_request( - commit_ready_request, - relay_host, - relay_port, - use_tls, - tlsca_cert_path, - conf, - ); + let request_id = &extinguish_request.session_id.to_string(); + let driver_address = get_driver_address_from_extinguish(extinguish_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request_id.to_string(), - message: "Ack of the commit prepare request".to_string(), - }; - return Ok(reply); + match result { + Ok(driver_info) => { + spawn_send_extinguish_request(driver_info, extinguish_request); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the commit prepare request failed. Driver not found {:?}", + e + ), + }); + } + } } fn send_commit_final_assertion_request( @@ -1400,7 +1424,6 @@ fn send_ack_final_receipt_request( conf: config::Config, ) -> Result { // TODO - println_step_heading("3.8".to_string()); let request_id = &ack_final_receipt_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); @@ -1425,32 +1448,37 @@ fn send_ack_final_receipt_request( } fn send_assign_asset_request( - commit_final_assertion_request: CommitFinalAssertionRequest, + assign_asset_request: AssignAssetRequest, conf: config::Config, ) -> Result { // TODO println_step_heading("3.6A".to_string()); - let request_id = &commit_final_assertion_request.session_id.to_string(); - let (relay_host, relay_port) = - get_relay_from_commit_final_assertion(commit_final_assertion_request.clone()); - let (use_tls, tlsca_cert_path) = - get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - - spawn_send_assign_asset_request( - commit_final_assertion_request, - relay_host, - relay_port, - use_tls, - tlsca_cert_path, - conf, - ); + let request_id = &assign_asset_request.session_id.to_string(); + let driver_address = get_driver_address_from_assign_asset(assign_asset_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); - let reply = Ack { - status: ack::Status::Ok as i32, - request_id: request_id.to_string(), - message: "Ack of the commit prepare request".to_string(), - }; - return Ok(reply); + match result { + Ok(driver_info) => { + spawn_send_assign_asset_request(driver_info, assign_asset_request); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit final assertion request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the commit final assertion request failed. Driver not found {:?}", + e + ), + }); + } + } } fn send_ack_final_receipt_broadcast_request( @@ -1458,6 +1486,7 @@ fn send_ack_final_receipt_broadcast_request( conf: config::Config, ) -> Result { // TODO + println_step_heading("3.8".to_string()); let request_id = &ack_final_receipt_request.session_id.to_string(); let (relay_host, relay_port) = get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); From e298f152e15294d7cc349bf06618985b3aa42ffd Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 11 Sep 2023 20:44:08 +0100 Subject: [PATCH 38/59] Added the resources required to assign an asset --- tools/go-gen-checksum.sh | 1 + .../core/drivers/fabric-driver/server/satp.ts | 213 +++- .../core/relay/src/services/satp_service.rs | 4 +- .../samples/fabric/satpsimpleasset/.gitignore | 4 + .../samples/fabric/satpsimpleasset/Makefile | 27 + .../fabric/satpsimpleasset/assetmgmt.go | 360 ++++++ .../fabric/satpsimpleasset/assetmgmt_test.go | 232 ++++ .../fabric/satpsimpleasset/bondasset.go | 327 +++++ .../fabric/satpsimpleasset/bondasset_test.go | 242 ++++ weaver/samples/fabric/satpsimpleasset/go.mod | 42 + weaver/samples/fabric/satpsimpleasset/go.sum | 157 +++ .../samples/fabric/satpsimpleasset/helper.go | 53 + weaver/samples/fabric/satpsimpleasset/main.go | 59 + .../fabric/satpsimpleasset/tokenasset.go | 316 +++++ .../fabric/satpsimpleasset/tokenasset_test.go | 326 +++++ .../fabric/interoperation-node-sdk/index.js | 1 + .../src/AssetManager.ts | 59 + .../src/SatpAssetManager.ts | 1111 +++++++++++++++++ .../interoperation-node-sdk/types/index.d.ts | 2 + .../fabric/dev/scripts/deployCC.sh | 4 + 20 files changed, 3519 insertions(+), 21 deletions(-) create mode 100644 weaver/samples/fabric/satpsimpleasset/.gitignore create mode 100644 weaver/samples/fabric/satpsimpleasset/Makefile create mode 100644 weaver/samples/fabric/satpsimpleasset/assetmgmt.go create mode 100644 weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go create mode 100644 weaver/samples/fabric/satpsimpleasset/bondasset.go create mode 100644 weaver/samples/fabric/satpsimpleasset/bondasset_test.go create mode 100644 weaver/samples/fabric/satpsimpleasset/go.mod create mode 100644 weaver/samples/fabric/satpsimpleasset/go.sum create mode 100644 weaver/samples/fabric/satpsimpleasset/helper.go create mode 100644 weaver/samples/fabric/satpsimpleasset/main.go create mode 100644 weaver/samples/fabric/satpsimpleasset/tokenasset.go create mode 100644 weaver/samples/fabric/satpsimpleasset/tokenasset_test.go create mode 100644 weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts diff --git a/tools/go-gen-checksum.sh b/tools/go-gen-checksum.sh index 87ef776051..513a5afd04 100755 --- a/tools/go-gen-checksum.sh +++ b/tools/go-gen-checksum.sh @@ -16,6 +16,7 @@ GOMODULE_PATHS=("weaver/core/network/fabric-interop-cc/libs/utils" "weaver/sdks/fabric/go-sdk" "weaver/samples/fabric/go-cli" "weaver/samples/fabric/simpleasset" +"weaver/samples/fabric/satpsimpleasset" "weaver/samples/fabric/simpleassetandinterop" "weaver/samples/fabric/simpleassettransfer" "weaver/samples/fabric/simplestatewithacl" diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index fea151a0c3..0f0eef77b5 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -5,7 +5,7 @@ import logger from './logger'; import { credentials } from '@grpc/grpc-js'; import { getNetworkConfig } from './helpers/helpers' -import { AssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' +import { SatpAssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' import fs from 'fs'; import path from 'path'; @@ -23,6 +23,7 @@ async function performLockHelper( networkName: string ): Promise { + // TODO: remove the hardcoded values let performLockRequest2 = {}; performLockRequest2['target-network'] = 'network1'; performLockRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; @@ -31,11 +32,12 @@ async function performLockHelper( performLockRequest2['recipient'] = 'bob'; performLockRequest2['param'] = 'bond01:a05'; - // Locker and Recipient + // Locker and recipient const locker = performLockRequest2['locker']; const recipient = performLockRequest2['recipient']; let hashFn = performLockRequest2['hash_fn']; let hashBase64 = performLockRequest2['hashBase64']; + const targetNetwork = performLockRequest2['target-network']; // Hash let hash: HashFunctions.Hash @@ -66,11 +68,11 @@ async function performLockHelper( } const params = performLockRequest2['param'].split(':') - const netConfig = getNetworkConfig(performLockRequest2['target-network']) + const netConfig = getNetworkConfig(targetNetwork) if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { console.error( - `Please use a valid --target-network. No valid environment found for ${performLockRequest2['target-network']} ` + `Please use a valid --target-network. No valid environment found for ${targetNetwork} ` ) return } @@ -79,7 +81,7 @@ async function performLockHelper( channel: netConfig.channelName, contractName: netConfig.chaincode, connProfilePath: netConfig.connProfilePath, - networkName: performLockRequest2['target-network'], + networkName: targetNetwork, mspId: netConfig.mspId, userString: locker }) @@ -92,14 +94,14 @@ async function performLockHelper( var funcToCall, asset if (performLockRequest2['fungible']) { - funcToCall = AssetManager.createFungibleHTLC + funcToCall = SatpAssetManager.createFungibleHTLC asset = 'Fungible Asset' } else { - funcToCall = AssetManager.createHTLC + funcToCall = SatpAssetManager.createHTLC asset = 'Asset' } - console.info(`Asset Exchange: Lock ${asset}:\n`); + console.info(`Asset Lock: Lock ${asset}:\n`); try { console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) // const res = await funcToCall(network.contract, @@ -113,14 +115,12 @@ async function performLockHelper( // throw new Error() // } // console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) - console.info('Asset Exchange: Lock Complete.') + console.info('Asset has been locked successfully') } catch (error) { - console.error(`Could not Lock ${asset} in ${performLockRequest2['target-network']}`) + console.error(`Could not Lock ${asset} in ${targetNetwork}`) } - // await new Promise(f => setTimeout(f, performLockRequest2['timeout-duration'] * 1000 + 3000)); - await network.gateway.disconnect() logger.info('Gateways disconnected.') @@ -136,7 +136,88 @@ async function createAssetHelper( networkName: string ): Promise { - // TODO + // TODO: remove the hardcoded values + let createAssetRequest2 = {}; + createAssetRequest2['target-network'] = 'network1'; + createAssetRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; + createAssetRequest2['timeout-duration'] = parseInt('3600'); + createAssetRequest2['owner'] = 'admin'; + createAssetRequest2['type'] = 'bond'; + createAssetRequest2['assetType'] = 'bond01'; + createAssetRequest2['id'] = 'a065'; + createAssetRequest2['issuer'] = 'admin'; + createAssetRequest2['facevalue'] = '300'; + createAssetRequest2['maturitydate'] = '05 May 48 00:00 MST'; + + const targetNetwork = createAssetRequest2['target-network']; + const owner = createAssetRequest2['owner']; + const ccType = createAssetRequest2['type']; + const assetType = createAssetRequest2['assetType']; + const id = createAssetRequest2['id']; + const issuer = createAssetRequest2['issuer']; + const facevalue = createAssetRequest2['facevalue']; + const maturitydate = createAssetRequest2['maturitydate']; + const tokenassettype = createAssetRequest2['tokenassettype']; + const numunits = createAssetRequest2['numunits']; + + const netConfig = getNetworkConfig(targetNetwork) + console.info(netConfig) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + console.error( + `Please use a valid --target-network. No valid environment found for ${targetNetwork} ` + ) + return + } + + const currentQuery = { + channel: netConfig.channelName, + contractName: netConfig.chaincode, + ccFunc: '', + args: [] + } + + const network = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: targetNetwork, + mspId: netConfig.mspId, + userString: owner, + registerUser: false + }) + + const userId = await network.wallet.get(owner) + const userCert = Buffer.from((userId).credentials.certificate).toString('base64') + + if (ccType == 'bond') { + currentQuery.ccFunc = 'CreateAsset' + currentQuery.args = [...currentQuery.args, assetType, id, userCert, issuer, facevalue, maturitydate] + } else if (ccType == 'token') { + currentQuery.ccFunc = 'IssueTokenAssets' + currentQuery.args = [...currentQuery.args, tokenassettype, numunits, userCert] + } else { + throw new Error(`Unrecognized asset category: ${ccType}`) + } + console.log(currentQuery) + + try { + console.info(`Trying creating the asset: type: ${ccType}, id: ${id}, by: ${owner}, facevalue: ${facevalue}, maturitydate: ${maturitydate}`) + const read = await network.contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + console.info('Asset has been created successfully') + } else { + logger.debug('No Response from network') + } + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } + + await network.gateway.disconnect() + logger.info('Gateways disconnected.') + const client = getRelayClientForAssetStatusResponse(); const request = new satp_pb.SendAssetStatusRequest(); request.setSessionId(createAssetRequest.getSessionId()); @@ -162,12 +243,106 @@ async function assignAssetHelper( networkName: string ): Promise { - // TODO - const client = getRelayClientForAssetStatusResponse(); - const request = new satp_pb.SendAssetStatusRequest(); - request.setSessionId(assignAssetRequest.getSessionId()); - request.setStatus("Finalized"); - client.sendAssetStatus(request, relayCallback); + // TODO: remove the hardcoded values + let assignAssetRequest2 = {}; + assignAssetRequest2['target-network'] = 'network1'; + assignAssetRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; + assignAssetRequest2['timeout-duration'] = parseInt('3600'); + assignAssetRequest2['locker'] = 'admin'; + assignAssetRequest2['recipient'] = 'bob'; + assignAssetRequest2['fungible'] = false; + assignAssetRequest2['contract-id'] = 'abc01'; + assignAssetRequest2['hash_fn'] = ''; + assignAssetRequest2['secret'] = 'secrettext'; + assignAssetRequest2['param'] = 'bond01:a065'; + + const targetNetwork = assignAssetRequest2['target-network']; + const locker = assignAssetRequest2['locker']; + const recipient = assignAssetRequest2['recipient']; + const fungible = assignAssetRequest2['fungible']; + const hashFn = assignAssetRequest2['hash_fn']; + const secret = assignAssetRequest2['secret']; + + // Hash + let hash: HashFunctions.Hash + if (hashFn == 'SHA512') { + hash = new HashFunctions.SHA512() + } else { + hash = new HashFunctions.SHA256() + } + hash.setPreimage(secret) + + let contractId: string = null, params + if (assignAssetRequest2['contract-id']) { + contractId = assignAssetRequest2['contract-id'] + } + + params = assignAssetRequest2['param'].split(':') + + const netConfig = getNetworkConfig(targetNetwork) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + console.error( + `Please use a valid --target-network. No valid environment found for ${targetNetwork} ` + ) + return + } + + const network = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: targetNetwork, + mspId: netConfig.mspId, + userString: recipient + }) + + var funcToCall = SatpAssetManager.assignAsset + var asset = assignAssetRequest2['param'] + + if (assignAssetRequest2['fungible']) { + // funcToCall = SatpAssetManager.claimFungibleAssetInHTLC + asset = 'Fungible Asset' + } + + if (fungible) { + try { + console.info(`Trying assigning the asset with contract id ${contractId}`) + + // TODO + } catch (error) { + console.error(`Could not assign ${asset} in ${targetNetwork}`) + throw new Error(`Could not assign ${asset} in ${targetNetwork}`) + } + } else { + try { + const lockerId = await network.wallet.get(locker) + const lockerCert = Buffer.from((lockerId).credentials.certificate).toString('base64') + + console.info(`Trying assign asset with params: ${params[0]}, ${params[1]} locked by ${locker} for ${recipient}`) + const res = await funcToCall(network.contract, + params[0], + params[1], + lockerCert, + hash) + if (!res) { + throw new Error() + } + console.info(`${asset} assigned complete: ${res}`) + console.info(`Asset ${asset} assign complete: ${res}`) + } catch (error) { + console.error(`Could not assign non-fungible ${asset} in ${targetNetwork}: ${error}`) + throw new Error(`Could not assign non-fungible ${asset} in ${targetNetwork}: ${error}`) + } + + await network.gateway.disconnect() + logger.info('Gateways disconnected.') + + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(assignAssetRequest.getSessionId()); + request.setStatus("Finalized"); + client.sendAssetStatus(request, relayCallback); + } } function getRelayClientForAssetStatusResponse() { diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index e33e3610d9..7ed1536339 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1414,7 +1414,7 @@ fn send_commit_final_assertion_request( let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), - message: "Ack of the commit prepare request".to_string(), + message: "Commit final assertion request sent".to_string(), }; return Ok(reply); } @@ -1442,7 +1442,7 @@ fn send_ack_final_receipt_request( let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), - message: "Ack of the commit prepare request".to_string(), + message: "Ack final receipt request sent".to_string(), }; return Ok(reply); } diff --git a/weaver/samples/fabric/satpsimpleasset/.gitignore b/weaver/samples/fabric/satpsimpleasset/.gitignore new file mode 100644 index 0000000000..6e83e63f95 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/.gitignore @@ -0,0 +1,4 @@ +satpsimpleasset +asset-mgmt +mocks +vendor diff --git a/weaver/samples/fabric/satpsimpleasset/Makefile b/weaver/samples/fabric/satpsimpleasset/Makefile new file mode 100644 index 0000000000..0b11edb7ab --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/Makefile @@ -0,0 +1,27 @@ +run-vendor: + go mod edit -replace github.com/hyperledger/cacti/weaver/common/protos-go/v2=../../../common/protos-go/ + go mod edit -replace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2=../../../core/network/fabric-interop-cc/interfaces/asset-mgmt/ + go mod edit -replace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils=../../../core/network/fabric-interop-cc/libs/testutils/ + go mod vendor + +undo-vendor: + rm -rf vendor + go mod edit -dropreplace github.com/hyperledger/cacti/weaver/common/protos-go/v2 + go mod edit -dropreplace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 + go mod edit -dropreplace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils + +build-local: run-vendor build undo-vendor + +test-local: run-vendor test undo-vendor + +build: + go build -v . + +test: + go test -v . + +clean-vendor: + rm -rf vendor + +clean: clean-vendor + rm satpsimpleasset diff --git a/weaver/samples/fabric/satpsimpleasset/assetmgmt.go b/weaver/samples/fabric/satpsimpleasset/assetmgmt.go new file mode 100644 index 0000000000..384c4c3c96 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/assetmgmt.go @@ -0,0 +1,360 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package main + +import ( + "encoding/json" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/cacti/weaver/common/protos-go/v2/common" + "github.com/hyperledger/fabric-contract-api-go/contractapi" + log "github.com/sirupsen/logrus" +) + +// asset specific checks (ideally an asset in a different application might implement checks specific to that asset) +func (s *SmartContract) BondAssetSpecificChecks(ctx contractapi.TransactionContextInterface, assetType, id string, lockInfoSerializedProto64 string) error { + + lockInfo, err := s.amc.ValidateAndExtractLockInfo(lockInfoSerializedProto64) + if err != nil { + return err + } + lockInfoHTLC := &common.AssetLockHTLC{} + err = proto.Unmarshal(lockInfo.LockInfo, lockInfoHTLC) + if err != nil { + return logThenErrorf("unmarshal error: %+v", err) + } + // ReadAsset should check both the existence and ownership of the asset for the locker + bond, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return logThenErrorf("failed reading the bond asset: %+v", err) + } + log.Infof("bond: %+v", *bond) + log.Infof("lockInfoHTLC: %+v", *lockInfoHTLC) + + // Check if asset doesn't mature before locking period + if uint64(bond.MaturityDate.Unix()) < lockInfoHTLC.ExpiryTimeSecs { + return logThenErrorf("cannot lock bond asset as it will mature before locking period") + } + + return nil +} + +// Ledger transaction (invocation) functions + +func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) { + + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetExchangeAgreementSerializedProto64) + if err != nil { + return "", err + } + err = s.BondAssetSpecificChecks(ctx, assetAgreement.AssetType, assetAgreement.Id, lockInfoSerializedProto64) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + contractId, err := s.amc.LockAsset(ctx, assetExchangeAgreementSerializedProto64, lockInfoSerializedProto64) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + // write to the ledger the details needed at the time of unlock/claim + err = s.amc.ContractIdAssetsLookupMap(ctx, assetAgreement.AssetType, assetAgreement.Id, contractId) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + return contractId, nil +} + +func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) { + + assetAgreement, err := s.amc.ValidateAndExtractFungibleAssetAgreement(fungibleAssetExchangeAgreementSerializedProto64) + if err != nil { + return "", err + } + lockInfo, err := s.amc.ValidateAndExtractLockInfo(lockInfoSerializedProto64) + if err != nil { + return "", err + } + lockInfoHTLC := &common.AssetLockHTLC{} + err = proto.Unmarshal(lockInfo.LockInfo, lockInfoHTLC) + if err != nil { + return "", logThenErrorf("unmarshal error: %+v", err) + } + + // Check if locker/transaction-creator has enough quantity of token assets to lock + lockerHasEnoughTokens, err := s.TokenAssetsExist(ctx, assetAgreement.AssetType, assetAgreement.NumUnits) + if err != nil { + return "", logThenErrorf(err.Error()) + } + if !lockerHasEnoughTokens { + return "", logThenErrorf("cannot lock token asset of type %s as there are not enough tokens", assetAgreement.AssetType) + } + + contractId, err := s.amc.LockFungibleAsset(ctx, fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + err = s.DeleteTokenAssets(ctx, assetAgreement.AssetType, assetAgreement.NumUnits) + if err != nil { + // not performing the operation UnlockFungibleAsset and let the TxCreator take care of it + return contractId, logThenErrorf(err.Error()) + } + + err = s.amc.ContractIdFungibleAssetsLookupMap(ctx, assetAgreement.AssetType, assetAgreement.NumUnits, contractId) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + return contractId, nil +} + +// Check whether this asset has been locked by anyone (not just by caller) +func (s *SmartContract) IsAssetLocked(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string) (bool, error) { + return s.amc.IsAssetLocked(ctx, assetAgreementSerializedProto64) +} + +// Check whether a bond asset has been locked using contractId by anyone (not just by caller) +func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + return s.amc.IsAssetLockedQueryUsingContractId(ctx, contractId) +} + +// Check whether a token asset has been locked using contractId by anyone (not just by caller) +func (s *SmartContract) IsFungibleAssetLocked(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + return s.amc.IsFungibleAssetLocked(ctx, contractId) +} + +func (s *SmartContract) ClaimAsset(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string, claimInfoSerializedProto64 string) (bool, error) { + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetAgreementSerializedProto64) + if err != nil { + return false, err + } + claimed, err := s.amc.ClaimAsset(ctx, assetAgreementSerializedProto64, claimInfoSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if claimed { + // Change asset ownership to claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset, err := getBondAsset(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset.Owner = string(recipientECertBase64) + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = ctx.GetStub().PutState(getBondAssetKey(assetAgreement.AssetType, assetAgreement.Id), assetJSON) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + err = s.amc.DeleteAssetLookupMaps(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf("failed to delete bond asset lookup maps: %+v", err) + } + + return true, nil + } else { + return false, logThenErrorf("claim on bond asset type %s with asset id %s failed", assetAgreement.AssetType, assetAgreement.Id) + } +} + +func (s *SmartContract) AssignAsset(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string, claimInfoSerializedProto64 string) (bool, error) { + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetAgreementSerializedProto64) + if err != nil { + return false, err + } + + // Change asset ownership to claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset, err := getBondAsset(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset.Owner = string(recipientECertBase64) + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = ctx.GetStub().PutState(getBondAssetKey(assetAgreement.AssetType, assetAgreement.Id), assetJSON) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + return true, nil +} + +func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) { + claimed, err := s.amc.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if claimed { + // Change asset ownership to claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + // Fetch the contracted bond asset type and id from the ledger + assetType, assetId, err := s.amc.FetchFromContractIdAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + asset, err := getBondAsset(ctx, assetType, assetId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset.Owner = recipientECertBase64 + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = ctx.GetStub().PutState(getBondAssetKey(assetType, assetId), assetJSON) + if err != nil { + return false, logThenErrorf(err.Error()) + } + // delete the lookup maps + err = s.amc.DeleteAssetLookupMapsUsingContractId(ctx, assetType, assetId, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + return true, nil + } else { + return false, logThenErrorf("claim on bond asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) ClaimFungibleAsset(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) { + claimed, err := s.amc.ClaimFungibleAsset(ctx, contractId, claimInfoSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if claimed { + // Add the claimed tokens into the wallet of the claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + // Fetch the contracted token asset type and numUnits from the ledger + assetType, numUnits, err := s.amc.FetchFromContractIdFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + err = s.IssueTokenAssets(ctx, assetType, numUnits, recipientECertBase64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = s.amc.DeleteFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + return true, nil + } else { + return false, logThenErrorf("claim on token asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) UnlockAsset(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string) (bool, error) { + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetAgreementSerializedProto64) + if err != nil { + return false, err + } + + unlocked, err := s.amc.UnlockAsset(ctx, assetAgreementSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if unlocked { + err = s.amc.DeleteAssetLookupMaps(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf("failed to delete bond asset lookup maps: %+v", err) + } + } else { + return false, logThenErrorf("unlock on bond asset type %s with asset id %s failed", assetAgreement.AssetType, assetAgreement.Id) + } + + return true, nil +} + +func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + unlocked, err := s.amc.UnlockAssetUsingContractId(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if unlocked { + // delete the lookup maps + err := s.amc.DeleteAssetLookupMapsOnlyUsingContractId(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + return true, nil + } else { + return false, logThenErrorf("unlock on bond asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) UnlockFungibleAsset(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + unlocked, err := s.amc.UnlockFungibleAsset(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if unlocked { + // Add the unlocked tokens into the wallet of the locker + lockerECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + // Fetch the contracted token asset type and numUnits from the ledger + assetType, numUnits, err := s.amc.FetchFromContractIdFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + err = s.IssueTokenAssets(ctx, assetType, numUnits, lockerECertBase64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = s.amc.DeleteFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + return true, nil + } else { + return false, logThenErrorf("unlock on token asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) GetHTLCHash(ctx contractapi.TransactionContextInterface, assetAgreementBytesBase64 string) (string, error) { + return s.amc.GetHTLCHash(ctx, assetAgreementBytesBase64) +} + +func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) { + return s.amc.GetHTLCHashByContractId(ctx, contractId) +} + +func (s *SmartContract) GetHTLCHashPreImage(ctx contractapi.TransactionContextInterface, assetAgreementBytesBase64 string) (string, error) { + return s.amc.GetHTLCHashPreImage(ctx, assetAgreementBytesBase64) +} + +func (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) { + return s.amc.GetHTLCHashPreImageByContractId(ctx, contractId) +} diff --git a/weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go b/weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go new file mode 100644 index 0000000000..83db59decd --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go @@ -0,0 +1,232 @@ +package main_test + +import ( + "encoding/json" + "encoding/base64" + "crypto/sha256" + "fmt" + "testing" + "time" + + mspProtobuf "github.com/hyperledger/fabric-protos-go/msp" + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric-chaincode-go/shim" + "github.com/stretchr/testify/require" + sa "github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset" + "github.com/hyperledger/cacti/weaver/common/protos-go/v2/common" + wtest "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils" +) + +// function that supplies value that is to be returned by ctx.GetStub().GetCreator() in locker/recipient context +func getCreatorInContext(creator string) string { + serializedIdentity := &mspProtobuf.SerializedIdentity{} + var eCertBytes []byte + if creator == "locker" { + eCertBytes, _ = base64.StdEncoding.DecodeString(getLockerECertBase64()) + } else { + eCertBytes, _ = base64.StdEncoding.DecodeString(getRecipientECertBase64()) + } + serializedIdentity.IdBytes = eCertBytes + serializedIdentity.Mspid = "ca.org1.example.com" + serializedIdentityBytes, _ := proto.Marshal(serializedIdentity) + + return string(serializedIdentityBytes) +} + +// function that supplies the ECert in base64 for locker (e.g., Alice) +func getLockerECertBase64() string { + eCertBase64 := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNyVENDQWxTZ0F3SUJBZ0lVSENXLzBtV0xhc2hISG9zd0xxVWhpK1FwREc4d0NnWUlLb1pJemowRUF3SXcKY2pFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1ROHdEUVlEVlFRSApFd1pFZFhKb1lXMHhHakFZQmdOVkJBb1RFVzl5WnpFdWJtVjBkMjl5YXpFdVkyOXRNUjB3R3dZRFZRUURFeFJqCllTNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQWVGdzB5TURBM01qa3dORE0yTURCYUZ3MHlNVEEzTWprd05EUXgKTURCYU1GMHhDekFKQmdOVkJBWVRBbFZUTVJjd0ZRWURWUVFJRXc1T2IzSjBhQ0JEWVhKdmJHbHVZVEVVTUJJRwpBMVVFQ2hNTFNIbHdaWEpzWldSblpYSXhEekFOQmdOVkJBc1RCbU5zYVdWdWRERU9NQXdHQTFVRUF4TUZkWE5sCmNqRXdXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBU3VoL3JWQ2Y4T0R1dzBJaG5yTTJpaWYyYTcKc0dUOEJJVjFQRURVM1NucUNsbWgrUlYvM0p5S2wvVHl0aHpOL1pWbktFL3R2NWQzZ1ZXYk5zdGM5NytTbzRIYwpNSUhaTUE0R0ExVWREd0VCL3dRRUF3SUhnREFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCUXgvaExZCkNORzRlekNxdmdUS0MvV3d1U1ZubURBZkJnTlZIU01FR0RBV2dCVFdENjArZUNIYkR5RDMzUFdiQ3hWdVFxTUEKcVRBZkJnTlZIUkVFR0RBV2doUnZZelV4TURNM05EY3pPREF1YVdKdExtTnZiVEJZQmdncUF3UUZCZ2NJQVFSTQpleUpoZEhSeWN5STZleUpvWmk1QlptWnBiR2xoZEdsdmJpSTZJaUlzSW1obUxrVnVjbTlzYkcxbGJuUkpSQ0k2CkluVnpaWEl4SWl3aWFHWXVWSGx3WlNJNkltTnNhV1Z1ZENKOWZUQUtCZ2dxaGtqT1BRUURBZ05IQURCRUFpQUYKbnNMNlV1eFRtSks5bmhkTU1QNWxWN3hueVlsMVd5RGl6RVFzZnd1T1p3SWdYY3duSE9hVURXWWpmWHRGU0k1eQp6WjltcjZQRWtSNER0VEhJUkZhTVYxOD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==" + + return eCertBase64 +} + +// function that supplies the ECert in base64 for recipient (e.g., Bob) +func getRecipientECertBase64() string { + eCertBase64 := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNzekNDQWxxZ0F3SUJBZ0lVSjk3ZDJaWUNkRkNHbFo5L3hmZHRlcUdMc1Jvd0NnWUlLb1pJemowRUF3SXcKY2pFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1ROHdEUVlEVlFRSApFd1pFZFhKb1lXMHhHakFZQmdOVkJBb1RFVzl5WnpFdWJtVjBkMjl5YXpFdVkyOXRNUjB3R3dZRFZRUURFeFJqCllTNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQWVGdzB5TURBM01qa3dORE0yTURCYUZ3MHlNVEEzTWprd05EUXgKTURCYU1HQXhDekFKQmdOVkJBWVRBbFZUTVJjd0ZRWURWUVFJRXc1T2IzSjBhQ0JEWVhKdmJHbHVZVEVVTUJJRwpBMVVFQ2hNTFNIbHdaWEpzWldSblpYSXhEakFNQmdOVkJBc1RCV0ZrYldsdU1SSXdFQVlEVlFRREV3bHZjbWN4CllXUnRhVzR3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFmbjRmVHRDclQ3WVMrZVI1WWRFVU8KMHRKWmJGaEtyYUdqeWVNM2tBTzNNN1VHdVBsUCtXcFdjNkNYUEx3bTNETHgrcjFhMUx6eW1KUWdaOVJjdXErcgpvNEhmTUlIY01BNEdBMVVkRHdFQi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlM2ClkxR1FCMXAwUlNBeWxjTTRxQTlZS0JkU2hEQWZCZ05WSFNNRUdEQVdnQlRXRDYwK2VDSGJEeUQzM1BXYkN4VnUKUXFNQXFUQWZCZ05WSFJFRUdEQVdnaFJ2WXpVeE1ETTNORGN6T0RBdWFXSnRMbU52YlRCYkJnZ3FBd1FGQmdjSQpBUVJQZXlKaGRIUnljeUk2ZXlKb1ppNUJabVpwYkdsaGRHbHZiaUk2SWlJc0ltaG1Ma1Z1Y205c2JHMWxiblJKClJDSTZJbTl5WnpGaFpHMXBiaUlzSW1obUxsUjVjR1VpT2lKaFpHMXBiaUo5ZlRBS0JnZ3Foa2pPUFFRREFnTkgKQURCRUFpQkwrSzAzVGFFeWJaRkdWMmMzSS81ZXlpMFBveGc2elZOWDJkajJWRlk5WWdJZ0w5ZlhzcWhaUEU0VApBSkU4ZVZqdWZaOVJnNERJWWloTVVTKzBPbGpWL3pBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t" + return eCertBase64 +} + +// function to generate a "SHA256" hash in base64 format for a given preimage +func generateSHA256HashInBase64Form(preimage string) string { + hasher := sha256.New() + hasher.Write([]byte(preimage)) + shaHash := hasher.Sum(nil) + shaHashBase64 := base64.StdEncoding.EncodeToString(shaHash) + return shaHashBase64 +} + +type ContractedFungibleAsset struct { + Type string `json:"type"` + NumUnits uint64 `json:"id"` +} + +// test case for "asset exchange" happy path +func TestExchangeBondAssetWithTokenAsset(t *testing.T) { + ctx, chaincodeStub := wtest.PrepMockStub() + sc := sa.SmartContract{} + sc.ConfigureInterop("interopcc") + + bondLocker := getLockerECertBase64() + bondRecipient := getRecipientECertBase64() + bondType := "bond" + bondId := "b01" + bondIssuer := "network1" + bondFaceValue := 1 + currentTime := time.Now() + bondMaturityDate := currentTime.Add(time.Hour * 24) // maturity date is 1 day after current time + + tokenType := "cbdc" + tokenIssuer := "network2" + tokenValue := 1 + numTokens := uint64(10) + tokensLocker := getRecipientECertBase64() + tokensRecipient := getLockerECertBase64() + + + // Create bond asset + // let ctx.GetStub().GetState() return that the bond asset didn't exist before + chaincodeStub.GetStateReturnsOnCall(0, nil, nil) + err := sc.CreateAsset(ctx, bondType, bondId, bondLocker, bondIssuer, bondFaceValue, bondMaturityDate.Format(time.RFC822)) + require.NoError(t, err) + + + // Create token asset type + chaincodeStub.GetStateReturnsOnCall(1, nil, nil) + res, err := sc.CreateTokenAssetType(ctx, tokenType, tokenIssuer, tokenValue) + require.NoError(t, err) + require.Equal(t, res, true) + + + // Issue token assets for Bob + tokenAssetType := sa.TokenAssetType { + Issuer: tokenIssuer, + Value: tokenValue, + } + tokenAssetTypeBytes, _ := json.Marshal(tokenAssetType) + chaincodeStub.GetStateReturnsOnCall(2, tokenAssetTypeBytes, nil) + walletMap := make(map[string]uint64) + tokensWallet := &sa.TokenWallet{WalletMap: walletMap} + tokensWalletBytes, _ := json.Marshal(tokensWallet) + chaincodeStub.GetStateReturnsOnCall(3, tokensWalletBytes, nil) + err = sc.IssueTokenAssets(ctx, tokenType, numTokens, getRecipientECertBase64()) + require.NoError(t, err) + + + // Lock bond asset in network1 by Alice for Bob + fmt.Println("*** Lock bond asset in network1 by Alice ***") + preimage := "abcd" + hashBase64 := generateSHA256HashInBase64Form(preimage) + defaultTimeLockSecs := uint64(300) // set default locking period as 5 minutes + currentTimeSecs := uint64(time.Now().Unix()) + bondContractId := "bond-contract" + lockInfoHTLC := &common.AssetLockHTLC { + HashBase64: []byte(hashBase64), + ExpiryTimeSecs: currentTimeSecs + defaultTimeLockSecs, + TimeSpec: common.TimeSpec_EPOCH, + } + lockInfoHTLCBytes, _ := proto.Marshal(lockInfoHTLC) + lockInfo := &common.AssetLock{ + LockInfo: lockInfoHTLCBytes, + } + lockInfoBytes, _ := proto.Marshal(lockInfo) + bondAgreement := &common.AssetExchangeAgreement { + AssetType: bondType, + Id: bondId, + Locker: bondLocker, + Recipient: bondRecipient, + } + bondAgreementBytes, _ := proto.Marshal(bondAgreement) + bondAsset := sa.BondAsset { + Type: bondType, + ID: bondId, + Owner: bondLocker, + Issuer: bondIssuer, + FaceValue: bondFaceValue, + MaturityDate: bondMaturityDate, + } + bondAssetBytes, err := json.Marshal(bondAsset) + chaincodeStub.GetCreatorReturnsOnCall(0, []byte(getCreatorInContext("locker")), nil) + chaincodeStub.GetStateReturnsOnCall(4, bondAssetBytes, nil) + chaincodeStub.InvokeChaincodeReturnsOnCall(0, shim.Success([]byte("false"))) + chaincodeStub.InvokeChaincodeReturnsOnCall(1, shim.Success([]byte(bondContractId))) + bondContractId, err = sc.LockAsset(ctx, base64.StdEncoding.EncodeToString(bondAgreementBytes), base64.StdEncoding.EncodeToString(lockInfoBytes)) + require.NoError(t, err) + require.NotEmpty(t, bondContractId) + + + // Lock token asset in network2 by Bob for Alice + fmt.Println("*** Lock token asset in network2 by Bob ***") + tokensContractId := "tokens-contract" + tokensAgreement := &common.FungibleAssetExchangeAgreement { + AssetType: tokenType, + NumUnits: numTokens, + Locker: tokensLocker, + Recipient: tokensRecipient, + } + tokensAgreementBytes, _ := proto.Marshal(tokensAgreement) + chaincodeStub.GetCreatorReturnsOnCall(1, []byte(getCreatorInContext("recipient")), nil) + tokenAssetType = sa.TokenAssetType { + Issuer: tokenIssuer, + Value: tokenValue, + } + tokenAssetTypeBytes, _ = json.Marshal(tokenAssetType) + chaincodeStub.GetStateReturnsOnCall(5, tokenAssetTypeBytes, nil) + walletMap = make(map[string]uint64) + walletMap[tokenType] = numTokens + tokensWallet = &sa.TokenWallet{WalletMap: walletMap} + tokensWalletBytes, _ = json.Marshal(tokensWallet) + chaincodeStub.GetStateReturnsOnCall(6, tokensWalletBytes, nil) + chaincodeStub.InvokeChaincodeReturnsOnCall(2, shim.Success([]byte(tokensContractId))) + chaincodeStub.GetCreatorReturnsOnCall(2, []byte(getCreatorInContext("recipient")), nil) + chaincodeStub.GetStateReturnsOnCall(7, tokenAssetTypeBytes, nil) + chaincodeStub.GetStateReturnsOnCall(8, tokensWalletBytes, nil) + tokensContractId, err = sc.LockFungibleAsset(ctx, base64.StdEncoding.EncodeToString(tokensAgreementBytes), base64.StdEncoding.EncodeToString(lockInfoBytes)) + require.NoError(t, err) + require.NotEmpty(t, tokensContractId) + + + // Claim token asset in network2 by Alice + fmt.Println("*** Claim token asset in network2 by Alice ***") + preimageBase64 := base64.StdEncoding.EncodeToString([]byte(preimage)) + claimInfoHTLC := &common.AssetClaimHTLC { + HashPreimageBase64: []byte(preimageBase64), + } + claimInfoHTLCBytes, _ := proto.Marshal(claimInfoHTLC) + claimInfo := &common.AssetClaim{ + ClaimInfo: claimInfoHTLCBytes, + LockMechanism: common.LockMechanism_HTLC, + } + claimInfoBytes, _ := proto.Marshal(claimInfo) + chaincodeStub.InvokeChaincodeReturnsOnCall(3, shim.Success(nil)) + chaincodeStub.GetCreatorReturnsOnCall(3, []byte(getCreatorInContext("locker")), nil) + chaincodeStub.GetCreatorReturnsOnCall(4, []byte(getCreatorInContext("locker")), nil) + tokenAssetType = sa.TokenAssetType { + Issuer: tokenIssuer, + Value: tokenValue, + } + tokenAssetTypeBytes, _ = json.Marshal(tokenAssetType) + contractedTokenAsset := ContractedFungibleAsset{ + Type: tokenType, + NumUnits: numTokens, + } + + contractedTokenAssetBytes, _ := json.Marshal(contractedTokenAsset) + chaincodeStub.GetStateReturnsOnCall(9, tokenAssetTypeBytes, nil) + chaincodeStub.GetStateReturnsOnCall(10, contractedTokenAssetBytes, nil) + chaincodeStub.GetStateReturnsOnCall(11, nil, nil) + _, err = sc.ClaimFungibleAsset(ctx, base64.StdEncoding.EncodeToString(tokensAgreementBytes), base64.StdEncoding.EncodeToString(claimInfoBytes)) + require.NoError(t, err) + + + // Claim bond asset in network1 by Bob + fmt.Println("*** Claim bond asset in network1 by Bob ***") + chaincodeStub.InvokeChaincodeReturnsOnCall(4, shim.Success(nil)) + chaincodeStub.InvokeChaincodeReturnsOnCall(5, shim.Success([]byte("true"))) + chaincodeStub.InvokeChaincodeReturnsOnCall(6, shim.Success([]byte("true"))) + chaincodeStub.GetCreatorReturnsOnCall(5, []byte(getCreatorInContext("recipient")), nil) + chaincodeStub.GetStateReturnsOnCall(12, bondAssetBytes, nil) + chaincodeStub.GetStateReturnsOnCall(13, []byte(bondContractId), nil) + _, err = sc.ClaimAsset(ctx, base64.StdEncoding.EncodeToString(bondAgreementBytes), base64.StdEncoding.EncodeToString(claimInfoBytes)) + require.NoError(t, err) + +} diff --git a/weaver/samples/fabric/satpsimpleasset/bondasset.go b/weaver/samples/fabric/satpsimpleasset/bondasset.go new file mode 100644 index 0000000000..e5cb7cbf1f --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/bondasset.go @@ -0,0 +1,327 @@ +package main + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "time" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/cacti/weaver/common/protos-go/v2/common" + "github.com/hyperledger/fabric-contract-api-go/contractapi" +) + + +type BondAsset struct { + Type string `json:"type"` + ID string `json:"id"` + Owner string `json:"owner"` + Issuer string `json:"issuer"` + FaceValue int `json:"facevalue"` + MaturityDate time.Time `json:"maturitydate"` +} + +func getBondAssetKey(assetType string, assetId string) string { + return assetType + assetId +} + +func getBondAsset(ctx contractapi.TransactionContextInterface, assetType, id string) (*BondAsset, error) { + assetJSON, err := ctx.GetStub().GetState(getBondAssetKey(assetType, id)) + if err != nil { + return nil, fmt.Errorf("failed to read asset record from world state: %v", err) + } + if assetJSON == nil { + return nil, fmt.Errorf("the asset %s does not exist", id) + } + + var asset BondAsset + err = json.Unmarshal(assetJSON, &asset) + if err != nil { + return nil, err + } + return &asset, nil +} + +// InitBondAssetLedger adds a base set of assets to the ledger +func (s *SmartContract) InitBondAssetLedger(ctx contractapi.TransactionContextInterface) error { + assets := []BondAsset{ + {Type: "t1", ID: "a01", Issuer: "Treasury" , Owner: "", FaceValue: 300, + MaturityDate: time.Date(2022, time.April, 1, 12, 0, 0, 0, time.UTC)}, + {Type: "t1", ID: "a02", Issuer: "Treasury" , Owner: "", FaceValue: 400, + MaturityDate: time.Date(2022, time.July, 1, 12, 0, 0, 0, time.UTC)}, + } + + for _, asset := range assets { + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + err = ctx.GetStub().PutState(getBondAssetKey(asset.Type, asset.ID), assetJSON) + if err != nil { + return fmt.Errorf("failed to put to world state. %v", err) + } + } + + return nil +} + +// CreateAsset issues a new asset to the world state with given details. +func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, assetType, id, owner, issuer string, faceValue int, maturityDate string) error { + if assetType == "" { + return fmt.Errorf("Asset type cannot be blank") + } + if id == "" { + return fmt.Errorf("Asset ID cannot be blank") + } + if owner == "" && issuer == "" { + return fmt.Errorf("Asset Owner and Issuer cannot both be blank") + } + exists, err := s.AssetExists(ctx, assetType, id) + if err != nil { + return err + } + if exists { + return fmt.Errorf("the asset %s already exists", id) + } + + md_time, err := time.Parse(time.RFC822, maturityDate) + if err != nil { + return fmt.Errorf("maturity date provided is not in correct format, please use this format: %s", time.RFC822) + } + + if md_time.Before(time.Now()) { + return fmt.Errorf("maturity date can not be in past.") + } + + asset := BondAsset{ + Type: assetType, + ID: id, + Owner: owner, + Issuer: issuer, + FaceValue: faceValue, + MaturityDate: md_time, + } + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// ReadAsset returns the asset stored in the world state with given id. +// This function is called with the parameter inUpdateOwnerContext value as false, except in the update-owner context +func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, assetType, id string) (*BondAsset, error) { + asset, err := getBondAsset(ctx, assetType, id) + if err != nil { + return nil, err + } + if !checkAccessToAsset(s, ctx, asset) { + return nil, fmt.Errorf("cannot access Bond Asset %s", id) + } + return asset, nil +} + +// DeleteAsset deletes an given asset from the world state. +func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, assetType, id string) error { + + // Read the asset (which internally check access) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + return ctx.GetStub().DelState(getBondAssetKey(asset.Type, asset.ID)) +} + + +// isCallerAssetOwner returns true only if the invoker of the transaction is also the asset owner +func isCallerAssetOwner(ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + caller, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + fmt.Println(err.Error()) + return false + } + return (asset.Owner == caller) +} + +// isBondAssetLocked returns true only if the asset is presently locked +func isBondAssetLocked(s *SmartContract, ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + bondAssetAgreement := &common.AssetExchangeAgreement{ + AssetType: asset.Type, + Id: asset.ID, + Recipient: "*", + Locker: asset.Owner, + } + bondAssetAgreementProtoSerialized, err := proto.Marshal(bondAssetAgreement) + if err != nil { + fmt.Println(err.Error()) + return false + } + bondAssetAgreementProto64 := base64.StdEncoding.EncodeToString(bondAssetAgreementProtoSerialized) + locked, err := s.IsAssetLocked(ctx, bondAssetAgreementProto64) + if err != nil { + fmt.Println(err.Error()) + return false + } + return locked +} + +// isBondAssetLockedForMe returns true only if the asset is presently locked for me +func isBondAssetLockedForMe(s *SmartContract, ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + bondAssetAgreement := &common.AssetExchangeAgreement{ + AssetType: asset.Type, + Id: asset.ID, + Recipient: "", + Locker: asset.Owner, + } + bondAssetAgreementProtoSerialized, err := proto.Marshal(bondAssetAgreement) + if err != nil { + fmt.Println(err.Error()) + return false + } + bondAssetAgreementProto64 := base64.StdEncoding.EncodeToString(bondAssetAgreementProtoSerialized) + locked, err := s.IsAssetLocked(ctx, bondAssetAgreementProto64) + if err != nil { + fmt.Println(err.Error()) + return false + } + return locked +} + +// checkAccessToAsset checks several conditions under which an asset can be put on hold (i.e., not available for regular business operation) +func checkAccessToAsset(s *SmartContract, ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + // Ensure that the client is the owner of the asset + if !isCallerAssetOwner(ctx, asset) { + fmt.Printf("Illegal update: caller is not owner of asset %s\n", asset.ID) + return false + } + + // Ensure that the asset is not locked + if isBondAssetLocked(s, ctx, asset) { + fmt.Printf("Cannot update attributes of locked asset %s\n", asset.ID) + return false + } + + return true +} + +// AssetExists returns true when asset with given ID exists in world state +func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, assetType, id string) (bool, error) { + assetJSON, err := ctx.GetStub().GetState(getBondAssetKey(assetType, id)) + if err != nil { + return false, fmt.Errorf("failed to read asset record from world state: %v", err) + } + + return assetJSON != nil, nil +} + +// IsAssetReleased returns true if asset maturity date elapses +func (s *SmartContract) IsAssetReleased(ctx contractapi.TransactionContextInterface, assetType, id string) (bool, error) { + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return false, err + } + currDate := time.Now() + if (currDate.After(asset.MaturityDate)) { + return true, nil + } + + return false, nil +} + +// UpdateOwner sets the owner of an asset to a new owner. +func (s *SmartContract) UpdateOwner(ctx contractapi.TransactionContextInterface, assetType, id string, newOwner string) error { + // Read asset (which internally checks access if it is free to modified) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + + asset.Owner = newOwner + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// UpdateMaturityDate sets the maturity date of the asset to an updated date as passed in the parameters. +func (s *SmartContract) UpdateMaturityDate(ctx contractapi.TransactionContextInterface, assetType, id string, newMaturityDate time.Time) error { + // Read asset (which internally checks access if it is free to modified) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + + asset.MaturityDate = newMaturityDate + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// UpdateFaceValue sets the face value of an asset to the new value passed. +func (s *SmartContract) UpdateFaceValue(ctx contractapi.TransactionContextInterface, assetType, id string, newFaceValue int) error { + // Read asset (which internally checks access if it is free to modified) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + + asset.FaceValue = newFaceValue + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// GetMyAssets returns the assets owner by the caller +func (s *SmartContract) GetMyAssets(ctx contractapi.TransactionContextInterface) ([]*BondAsset, error) { + assets, err := s.GetAllAssets(ctx) + if err != nil { + return nil, err + } + + var myassets []*BondAsset + + for _, asset := range assets { + if checkAccessToAsset(s, ctx, asset) { + myassets = append(myassets, asset) + } + } + return myassets, nil +} + +// GetAllAssets returns all assets found in world state +func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*BondAsset, error) { + // range query with empty string for startKey and endKey does an + // open-ended query of all assets in the chaincode namespace. + resultsIterator, err := ctx.GetStub().GetStateByRange("", "") + if err != nil { + return nil, err + } + defer resultsIterator.Close() + + var assets []*BondAsset + for resultsIterator.HasNext() { + queryResponse, err := resultsIterator.Next() + if err != nil { + return nil, err + } + + var asset BondAsset + err = json.Unmarshal(queryResponse.Value, &asset) + if err != nil { + return nil, err + } + assets = append(assets, &asset) + } + + return assets, nil +} diff --git a/weaver/samples/fabric/satpsimpleasset/bondasset_test.go b/weaver/samples/fabric/satpsimpleasset/bondasset_test.go new file mode 100644 index 0000000000..b43170e23a --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/bondasset_test.go @@ -0,0 +1,242 @@ +package main_test + +import ( + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/hyperledger/fabric-protos-go/ledger/queryresult" + sa "github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset" + "github.com/stretchr/testify/require" + wtest "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils" + wtestmocks "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils/mocks" +) + +const ( + defaultAssetType = "BearerBonds" + defaultAssetId = "asset1" + defaultAssetOwner = "Alice" + defaultAssetIssuer = "Treasury" +) + +func TestInitBondAssetLedger(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + err := simpleAsset.InitBondAssetLedger(transactionContext) + require.NoError(t, err) + + chaincodeStub.PutStateReturns(fmt.Errorf("failed inserting key")) + err = simpleAsset.InitBondAssetLedger(transactionContext) + require.EqualError(t, err, "failed to put to world state. failed inserting key") +} + +func TestCreateAsset(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + err := simpleAsset.CreateAsset(transactionContext, "", "", "", "", 0, "02 Jan 26 15:04 MST") + require.Error(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, "", "", "", 0, "02 Jan 26 15:04 MST") + require.Error(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, "", "", 0, "02 Jan 26 15:04 MST") + require.Error(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "02 Jan 26 15:04 MST") + require.NoError(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, "", defaultAssetIssuer, 0, "02 Jan 26 15:04 MST") + require.NoError(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "02 Jan 06 15:04 MST") + require.EqualError(t, err, "maturity date can not be in past.") + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "") + require.EqualError(t, err, "maturity date provided is not in correct format, please use this format: 02 Jan 06 15:04 MST") + + chaincodeStub.GetStateReturns([]byte{}, nil) + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "") + require.EqualError(t, err, "the asset asset1 already exists") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestReadAsset(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + expectedAsset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + asset, err := simpleAsset.ReadAsset(transactionContext, "", "") + require.NoError(t, err) + require.Equal(t, expectedAsset, asset) + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + _, err = simpleAsset.ReadAsset(transactionContext, "", "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") + + chaincodeStub.GetStateReturns(nil, nil) + asset, err = simpleAsset.ReadAsset(transactionContext, "", "asset1") + require.EqualError(t, err, "the asset asset1 does not exist") + require.Nil(t, asset) +} + +func TestUpdateFaceValue(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + expectedAsset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleAsset.UpdateFaceValue(transactionContext, "", "", 0) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, nil) + err = simpleAsset.UpdateFaceValue(transactionContext, "", "asset1", 0) + require.EqualError(t, err, "the asset asset1 does not exist") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.UpdateFaceValue(transactionContext, "", "asset1", 0) + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestUpdateMaturityDate(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + expectedAsset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleAsset.UpdateMaturityDate(transactionContext, "", "", time.Now()) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, nil) + err = simpleAsset.UpdateMaturityDate(transactionContext, "", "asset1", time.Now()) + require.EqualError(t, err, "the asset asset1 does not exist") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.UpdateMaturityDate(transactionContext, "", "asset1", time.Now()) + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestDeleteAsset(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + asset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(nil) + err = simpleAsset.DeleteAsset(transactionContext, "", "") + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, nil) + err = simpleAsset.DeleteAsset(transactionContext, "", "asset1") + require.EqualError(t, err, "the asset asset1 does not exist") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.DeleteAsset(transactionContext, "", "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestUpdateOwner(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + asset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleAsset.UpdateOwner(transactionContext, "", "", "") + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.UpdateOwner(transactionContext, "", "", "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestGetMyAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + iterator := &wtestmocks.StateQueryIterator{} + + asset := &sa.BondAsset{ID: "asset1", Owner: getTestTxCreatorECertBase64()} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + iterator.HasNextReturnsOnCall(0, true) + iterator.HasNextReturnsOnCall(1, false) + iterator.NextReturns(&queryresult.KV{Value: bytes}, nil) + + chaincodeStub.GetCreatorReturns([]byte(getCreator()), nil) + + chaincodeStub.GetStateByRangeReturns(iterator, nil) + assets, err := simpleAsset.GetAllAssets(transactionContext) + require.NoError(t, err) + require.Equal(t, []*sa.BondAsset{asset}, assets) + + iterator.HasNextReturns(true) + iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving next item") + require.Nil(t, assets) + + chaincodeStub.GetStateByRangeReturns(nil, fmt.Errorf("failed retrieving all assets")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving all assets") + require.Nil(t, assets) +} + +func TestGetAllAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + iterator := &wtestmocks.StateQueryIterator{} + + asset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + iterator.HasNextReturnsOnCall(0, true) + iterator.HasNextReturnsOnCall(1, false) + iterator.NextReturns(&queryresult.KV{Value: bytes}, nil) + + chaincodeStub.GetStateByRangeReturns(iterator, nil) + assets, err := simpleAsset.GetAllAssets(transactionContext) + require.NoError(t, err) + require.Equal(t, []*sa.BondAsset{asset}, assets) + + iterator.HasNextReturns(true) + iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving next item") + require.Nil(t, assets) + + chaincodeStub.GetStateByRangeReturns(nil, fmt.Errorf("failed retrieving all assets")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving all assets") + require.Nil(t, assets) +} diff --git a/weaver/samples/fabric/satpsimpleasset/go.mod b/weaver/samples/fabric/satpsimpleasset/go.mod new file mode 100644 index 0000000000..a7d64f87cf --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/go.mod @@ -0,0 +1,42 @@ +module github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset + +go 1.20 + +require ( + github.com/golang/protobuf v1.5.3 + github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 + github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 + github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils v0.0.0-20210920170720-5d5bf2a54081 + github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a + github.com/hyperledger/fabric-contract-api-go v1.2.1 + github.com/hyperledger/fabric-protos-go v0.3.0 + github.com/sirupsen/logrus v1.9.0 + github.com/stretchr/testify v1.8.2 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/spec v0.20.8 // indirect + github.com/go-openapi/swag v0.21.1 // indirect + github.com/gobuffalo/envy v1.10.1 // indirect + github.com/gobuffalo/packd v1.0.1 // indirect + github.com/gobuffalo/packr v1.30.1 // indirect + github.com/joho/godotenv v1.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.8.1 // indirect + 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.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect + google.golang.org/grpc v1.54.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/weaver/samples/fabric/satpsimpleasset/go.sum b/weaver/samples/fabric/satpsimpleasset/go.sum new file mode 100644 index 0000000000..23646b5a4f --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/go.sum @@ -0,0 +1,157 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU= +github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.10.1 h1:ppDLoXv2feQ5nus4IcgtyMdHQkKng2lhJCIm33cblM0= +github.com/gobuffalo/envy v1.10.1/go.mod h1:AWx4++KnNOW3JOeEvhSaq+mvgAvnMYOY1XSIin4Mago= +github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= +github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY= +github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= +github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= +github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a h1:HwSCxEeiBthwcazcAykGATQ36oG9M+HEQvGLvB7aLvA= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a/go.mod h1:TDSu9gxURldEnaGSFbH1eMlfSQBWQcMQfnDBcpQv5lU= +github.com/hyperledger/fabric-contract-api-go v1.2.1 h1:Ww9cKH/qHl5s6WqF+Ts5ju5eaBxC/awB/BJE+rOsEkM= +github.com/hyperledger/fabric-contract-api-go v1.2.1/go.mod h1:BhWve0gz1iH+Xc+cO3rmeIZI7YaTWOQodka9CgeUOgo= +github.com/hyperledger/fabric-protos-go v0.3.0 h1:MXxy44WTMENOh5TI8+PCK2x6pMj47Go2vFRKDHB2PZs= +github.com/hyperledger/fabric-protos-go v0.3.0/go.mod h1:WWnyWP40P2roPmmvxsUXSvVI/CF6vwY1K1UFidnKBys= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +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/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.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +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.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +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 v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +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-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha-prerelease h1:MpVTzM8FvQ+2Qij/0DH0cGy2NoC1S5gD5c40HuEQlsI= +github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha-prerelease/go.mod h1:3DmkYfZoc+TtcAgF3kX6CmQDNKKKCHgbaoQuYu/3ayc= +github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha-prerelease h1:kks9cM6vS3raV6Ag6FTddFdy11LvUAc6oYHVRUU95ts= +github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha-prerelease/go.mod h1:jzOMrtkM1AwBUgfedRs7FkcZpl1g/eRe1wnQO9GEoio= +github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 h1:r7RknfMWs/riL4saBB31iWfRaP03AJuo19K2ettHP3E= +github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1/go.mod h1:3DmkYfZoc+TtcAgF3kX6CmQDNKKKCHgbaoQuYu/3ayc= +github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 h1:ssYji+cWvfnPYRBQyx7J/aBVTaVdHbb2gOQOLfVZRCw= +github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1/go.mod h1:zei2BRZv+Ln+3o5yr7K900LRpEDCiado8px0hoGuuco= diff --git a/weaver/samples/fabric/satpsimpleasset/helper.go b/weaver/samples/fabric/satpsimpleasset/helper.go new file mode 100644 index 0000000000..efca833cc7 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/helper.go @@ -0,0 +1,53 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// helper contains miscelaneous helper functions used throughout the code +package main + +import ( + "fmt" + "errors" + "encoding/base64" + "bytes" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric-contract-api-go/contractapi" + mspProtobuf "github.com/hyperledger/fabric-protos-go/msp" + log "github.com/sirupsen/logrus" +) + +// functions to log and return errors +func logThenErrorf(format string, args ...interface{}) error { + errorMsg := fmt.Sprintf(format, args...) + log.Error(errorMsg) + return errors.New(errorMsg) +} + +func getECertOfTxCreatorBase64(ctx contractapi.TransactionContextInterface) (string, error) { + + txCreatorBytes, err := ctx.GetStub().GetCreator() + if err != nil { + return "", fmt.Errorf("unable to get the transaction creator information: %+v", err) + } + + serializedIdentity := &mspProtobuf.SerializedIdentity{} + err = proto.Unmarshal(txCreatorBytes, serializedIdentity) + if err != nil { + return "", fmt.Errorf("getECertOfTxCreatorBase64: unmarshal error: %+v", err) + } + + eCertBytesBase64 := base64.StdEncoding.EncodeToString(serializedIdentity.IdBytes) + + return eCertBytesBase64, nil +} + +func createKeyValuePairs(m map[string]uint64) string { + b := new(bytes.Buffer) + for key, value := range m { + fmt.Fprintf(b, "%s=\"%d\"\n", key, value) + } + return b.String() +} diff --git a/weaver/samples/fabric/satpsimpleasset/main.go b/weaver/samples/fabric/satpsimpleasset/main.go new file mode 100644 index 0000000000..0b8c5b9d71 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/main.go @@ -0,0 +1,59 @@ +package main + +import ( + "fmt" + "os" + + "github.com/hyperledger/fabric-chaincode-go/shim" + "github.com/hyperledger/fabric-contract-api-go/contractapi" + am "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2" +) + +// SmartContract provides functions for managing an BondAsset and TokenAsset +type SmartContract struct { + contractapi.Contract + amc am.AssetManagementContract +} + +func (s *SmartContract) ConfigureInterop(interopChaincodeId string) { + s.amc.Configure(interopChaincodeId) +} + +func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface, ccType string, interopChaincodeId string) error { + s.ConfigureInterop(interopChaincodeId) + if ccType == "Bond" { + return s.InitBondAssetLedger(ctx) + } else if ccType == "Token" { + return s.InitTokenAssetLedger(ctx) + } + return fmt.Errorf("only Bond and Token are accepted as ccType.") +} + +func main() { + chaincode, err := contractapi.NewChaincode(new(SmartContract)) + + if err != nil { + fmt.Printf("Error creating chaincode: %s", err.Error()) + return + } + + _, ok := os.LookupEnv("EXTERNAL_SERVICE") + if ok { + server := &shim.ChaincodeServer{ + CCID: os.Getenv("CHAINCODE_CCID"), + Address: os.Getenv("CHAINCODE_ADDRESS"), + CC: chaincode, + TLSProps: shim.TLSProperties{ + Disabled: true, + }, + } + // Start the chaincode external server + err = server.Start() + } else { + err = chaincode.Start() + } + if err != nil { + fmt.Printf("Error starting chaincode: %s", err.Error()) + } + +} diff --git a/weaver/samples/fabric/satpsimpleasset/tokenasset.go b/weaver/samples/fabric/satpsimpleasset/tokenasset.go new file mode 100644 index 0000000000..972d90399a --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/tokenasset.go @@ -0,0 +1,316 @@ +package main + +import ( + "encoding/json" + "fmt" + + "github.com/hyperledger/fabric-contract-api-go/contractapi" +) + +type TokenAssetType struct { + Issuer string `json:"issuer"` + Value int `json:"value"` +} +type TokenWallet struct { + WalletMap map[string]uint64 `json:"walletlist"` +} + + +// InitTokenAssetLedger adds a base set of assets to the ledger +func (s *SmartContract) InitTokenAssetLedger(ctx contractapi.TransactionContextInterface) error { + _, err := s.CreateTokenAssetType(ctx, "token1", "CentralBank", 1) + if err != nil { + return err + } + return err +} + +// CreateTokenAssetType issues a new token asset type to the world state with given details. +func (s *SmartContract) CreateTokenAssetType(ctx contractapi.TransactionContextInterface, tokenAssetType string, issuer string, value int) (bool, error) { + if tokenAssetType == "" { + return false, fmt.Errorf("Token asset type cannot be blank") + } + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return false, err + } + if exists { + return false, fmt.Errorf("the token asset type %s already exists.", tokenAssetType) + } + + asset := TokenAssetType{ + Issuer: issuer, + Value: value, + } + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, err + } + id := getTokenAssetTypeId(tokenAssetType) + err = ctx.GetStub().PutState(id, assetJSON) + + if err != nil { + return false, fmt.Errorf("failed to create token asset type %s. %v", tokenAssetType, err) + } + return true, nil +} + +// ReadTokenAssetType returns the token asset type stored in the world state with given type. +func (s *SmartContract) ReadTokenAssetType(ctx contractapi.TransactionContextInterface, tokenAssetType string) (*TokenAssetType, error) { + id := getTokenAssetTypeId(tokenAssetType) + assetJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return nil, fmt.Errorf("failed to read token asset type %s: %v", tokenAssetType, err) + } + if assetJSON == nil { + return nil, fmt.Errorf("the token asset type %s does not exist.", tokenAssetType) + } + + var fat TokenAssetType + err = json.Unmarshal(assetJSON, &fat) + if err != nil { + return nil, err + } + + return &fat, nil +} + +// DeleteTokenAssetType deletes an given token asset type from the world state. +func (s *SmartContract) DeleteTokenAssetType(ctx contractapi.TransactionContextInterface, tokenAssetType string) error { + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the token asset type %s does not exist.", tokenAssetType) + } + + id := getTokenAssetTypeId(tokenAssetType) + err = ctx.GetStub().DelState(id) + if err != nil { + return fmt.Errorf("failed to delete token asset type %s: %v", tokenAssetType, err) + } + return nil +} + +// TokenAssetTypeExists returns true when token asset type with given ID exists in world state +func (s *SmartContract) TokenAssetTypeExists(ctx contractapi.TransactionContextInterface, tokenAssetType string) (bool, error) { + id := getTokenAssetTypeId(tokenAssetType) + assetJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return false, fmt.Errorf("failed to read from world state: %v", err) + } + + return assetJSON != nil, nil +} + +// IssueTokenAssets issues new token assets to an owner. +func (s *SmartContract) IssueTokenAssets(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, owner string) error { + if owner == "" { + return fmt.Errorf("Owner cannot be blank") + } + + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("cannot issue: the token asset type %s does not exist", tokenAssetType) + } + + id := getWalletId(owner) + return addTokenAssetsHelper(ctx, tokenAssetType, numUnits, id) +} + +// DeleteTokenAssets burns the token assets from an owner. +func (s *SmartContract) DeleteTokenAssets(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64) error { + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return err + } + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the token asset type %s does not exist", tokenAssetType) + } + + id := getWalletId(owner) + return subTokenAssetsHelper(ctx, tokenAssetType, numUnits, id) +} + +// TransferTokenAssets transfers the token assets from client's account to newOwner +func (s *SmartContract) TransferTokenAssets(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, newOwner string) error { + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the token asset type %s does not exist", tokenAssetType) + } + + if newOwner == "" { + return fmt.Errorf("New owner cannot be blank") + } + + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return err + } + + ownerId := getWalletId(owner) + newOwnerId := getWalletId(newOwner) + + err = subTokenAssetsHelper(ctx, tokenAssetType, numUnits, ownerId) + if err != nil { + return err + } + return addTokenAssetsHelper(ctx, tokenAssetType, numUnits, newOwnerId) +} + +// GetBalance returns the amount of given token asset type owned by an owner. +func (s *SmartContract) GetBalance(ctx contractapi.TransactionContextInterface, tokenAssetType string, owner string) (uint64, error) { + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return 0, err + } + if !exists { + return 0, fmt.Errorf("the token asset type %s does not exist", tokenAssetType) + } + + id := getWalletId(owner) + walletJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return 0, fmt.Errorf("failed to read owner's wallet from world state: %v", err) + } + if walletJSON == nil { + return 0, fmt.Errorf("owner does not have a wallet") + } + + var wallet TokenWallet + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return 0, err + } + balance := wallet.WalletMap[tokenAssetType] + return balance, nil +} + +// GetMyWallet returns the available amount for each token asset type owned by an owner. +func (s *SmartContract) GetMyWallet(ctx contractapi.TransactionContextInterface) (string, error) { + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return "", err + } + + id := getWalletId(owner) + walletJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return "", fmt.Errorf("failed to read owner's wallet from world state: %v", err) + } + if walletJSON == nil { + return "", fmt.Errorf("owner does not have a wallet") + } + + var wallet TokenWallet + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return "", err + } + return createKeyValuePairs(wallet.WalletMap), nil +} + +// Checks if owner has some given amount of token asset +func (s *SmartContract) TokenAssetsExist(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64) (bool, error) { + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, err + } + balance, err := s.GetBalance(ctx, tokenAssetType, owner) + if err != nil { + return false, err + } + return balance >= numUnits, nil +} + +// Helper Functions for token asset +func addTokenAssetsHelper(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, id string) error { + walletJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return logThenErrorf("failed to retrieve entry from ledger: %+v", err) + } + var wallet TokenWallet + if walletJSON != nil { + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return err + } + balance := wallet.WalletMap[tokenAssetType] + wallet.WalletMap[tokenAssetType] = balance + numUnits + } else { + walletMap := make(map[string]uint64) + walletMap[tokenAssetType] = numUnits + wallet = TokenWallet{ + WalletMap: walletMap, + } + } + + walletNewJSON, err := json.Marshal(wallet) + if err != nil { + return err + } + return ctx.GetStub().PutState(id, walletNewJSON) +} + +func subTokenAssetsHelper(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, id string) error { + walletJSON, err := ctx.GetStub().GetState(id) + var wallet TokenWallet + if err != nil { + return err + } + if walletJSON == nil { + return fmt.Errorf("owner does not have a wallet") + } + + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return err + } + + // Check if owner has sufficient amount of given type to delete + _, exists := wallet.WalletMap[tokenAssetType] + if !exists { + return fmt.Errorf("the owner does not possess any units of the token asset type %s", tokenAssetType) + } + if wallet.WalletMap[tokenAssetType] < numUnits { + return fmt.Errorf("the owner does not possess enough units of the token asset type %s", tokenAssetType) + } + + // Subtract after all checks + wallet.WalletMap[tokenAssetType] -= numUnits + + // Delete token asset type from map if num of units becomes zero + if wallet.WalletMap[tokenAssetType] == 0 { + delete(wallet.WalletMap, tokenAssetType) + } + + if len(wallet.WalletMap) == 0 { + // Delete the entry from State if wallet becomes empty + return ctx.GetStub().DelState(id) + } else { + // Update the new wallet object otherwise + walletNewJSON, err := json.Marshal(wallet) + if err != nil { + return err + } + return ctx.GetStub().PutState(id, walletNewJSON) + } +} + +func getTokenAssetTypeId(tokenAssetType string) string { + return "FAT_" + tokenAssetType +} +func getWalletId(owner string) string { + return "W_" + owner +} diff --git a/weaver/samples/fabric/satpsimpleasset/tokenasset_test.go b/weaver/samples/fabric/satpsimpleasset/tokenasset_test.go new file mode 100644 index 0000000000..facbfb393f --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/tokenasset_test.go @@ -0,0 +1,326 @@ +package main_test + +import ( + "encoding/json" + "fmt" + "testing" + "encoding/base64" + "bytes" + + "github.com/golang/protobuf/proto" + mspProtobuf "github.com/hyperledger/fabric-protos-go/msp" + sa "github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset" + "github.com/stretchr/testify/require" + wtest "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils" +) + +func TestInitTokenAssetLedger(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + err := simpleToken.InitTokenAssetLedger(transactionContext) + require.NoError(t, err) + + chaincodeStub.PutStateReturns(fmt.Errorf("failed inserting key")) + err = simpleToken.InitTokenAssetLedger(transactionContext) + require.EqualError(t, err, "failed to create token asset type token1. failed inserting key") +} + +func TestCreateTokenAssetType(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + // Should fail if token asset type is empty + res, err := simpleToken.CreateTokenAssetType(transactionContext, "", "", 0) + require.Error(t, err) + + // Successful Case + res, err = simpleToken.CreateTokenAssetType(transactionContext, "sometokentype", "", 0) + require.NoError(t, err) + require.Equal(t, res, true) + + // Check if tokenAssetType already exists + chaincodeStub.GetStateReturns([]byte{}, nil) + res, err = simpleToken.CreateTokenAssetType(transactionContext, "token1", "", 0) + require.EqualError(t, err, "the token asset type token1 already exists.") + require.Equal(t, res, false) + + // Check if PutState fails + chaincodeStub.GetStateReturns(nil, nil) + chaincodeStub.PutStateReturns(fmt.Errorf("failed to put state")) + res, err = simpleToken.CreateTokenAssetType(transactionContext, "token1", "", 0) + require.EqualError(t, err, "failed to create token asset type token1. failed to put state") + require.Equal(t, res, false) + + // Check if GetState fails + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + res, err = simpleToken.CreateTokenAssetType(transactionContext, "token1", "", 0) + require.EqualError(t, err, "failed to read from world state: unable to retrieve asset") + require.Equal(t, res, false) +} + +func TestReadTokenAssetType(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + expectedAsset := &sa.TokenAssetType{Issuer: "CentralBank", Value: 10} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Successful Read + chaincodeStub.GetStateReturns(bytes, nil) + asset, err := simpleToken.ReadTokenAssetType(transactionContext, "") + require.NoError(t, err) + require.Equal(t, expectedAsset, asset) + + // GetState Fail case + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + _, err = simpleToken.ReadTokenAssetType(transactionContext, "") + require.EqualError(t, err, "failed to read token asset type : unable to retrieve asset") + + // token asset type does not exist + chaincodeStub.GetStateReturns(nil, nil) + asset, err = simpleToken.ReadTokenAssetType(transactionContext, "token1") + require.EqualError(t, err, "the token asset type token1 does not exist.") + require.Nil(t, asset) +} + +func TestDeleteTokenAssetType(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + chaincodeStub.DelStateReturns(nil) + err := simpleToken.DeleteTokenAssetType(transactionContext, "") + require.EqualError(t, err, "the token asset type does not exist.") + + bytes, err := json.Marshal(true) + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(fmt.Errorf("unable to retrieve asset")) + err = simpleToken.DeleteTokenAssetType(transactionContext, "token1") + require.EqualError(t, err, "failed to delete token asset type token1: unable to retrieve asset") + + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(nil) + err = simpleToken.DeleteTokenAssetType(transactionContext, "token1") + require.NoError(t, err) +} + +func TestIssueTokenAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Should fail of owner is blank + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "") + require.Error(t, err) + + // Checking succesful case + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "someowner") + require.NoError(t, err) + + // Check if writing state after issuing fails + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.PutStateReturns(fmt.Errorf("failed to put state")) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "someowner") + require.EqualError(t, err, "failed to put state") + + // Error check + chaincodeStub.GetStateReturns(nil, fmt.Errorf("failed to read state")) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "someowner") + require.EqualError(t, err, "failed to read from world state: failed to read state") + + // Check if given token asset type doesn't exist + chaincodeStub.GetStateReturns(nil, nil) + err = simpleToken.IssueTokenAssets(transactionContext, "token1", 0, "someowner") + require.EqualError(t, err, "cannot issue: the token asset type token1 does not exist") +} + +func TestDeleteTokenAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Successful delete case + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.DeleteTokenAssets(transactionContext, "token1", 2) + require.NoError(t, err) + + // Trying to delete more than owner hass + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.DeleteTokenAssets(transactionContext, "token1", 10) + require.EqualError(t, err, "the owner does not possess enough units of the token asset type token1") + + // Trying to delete token that owner doesn't possess + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.DeleteTokenAssets(transactionContext, "token2", 2) + require.EqualError(t, err, "the owner does not possess any units of the token asset type token2") + + // Error Check + chaincodeStub.GetStateReturns(nil, fmt.Errorf("Failed to read state")) + err = simpleToken.DeleteTokenAssets(transactionContext, "", 0) + require.EqualError(t, err, "failed to read from world state: Failed to read state") + + // check if it tries to delete wallet entry when wallet list is empty + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(fmt.Errorf("Failed to delete state")) + err = simpleToken.DeleteTokenAssets(transactionContext, "token1", 5) + require.EqualError(t, err, "Failed to delete state") + +} +func TestTransferTokenAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.TransferTokenAssets(transactionContext, "token1", 2, "") + require.Error(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.TransferTokenAssets(transactionContext, "token1", 2, "newowner") + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.TransferTokenAssets(transactionContext, "token1", 10, "newowner") + require.EqualError(t, err, "the owner does not possess enough units of the token asset type token1") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("Failed to read state")) + err = simpleToken.DeleteTokenAssets(transactionContext, "", 0) + require.EqualError(t, err, "failed to read from world state: Failed to read state") +} +func TestGetBalance(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Successful GetBalance case + chaincodeStub.GetStateReturnsOnCall(0, bytes, nil) + chaincodeStub.GetStateReturnsOnCall(1, bytes, nil) + bal, err := simpleToken.GetBalance(transactionContext, "token1", "") + require.NoError(t, err) + require.Equal(t, bal, uint64(5)) + + // GetState Fails + chaincodeStub.GetStateReturnsOnCall(2, nil, fmt.Errorf("Failed to read state")) + bal, err = simpleToken.GetBalance(transactionContext, "", "") + require.EqualError(t, err, "failed to read from world state: Failed to read state") + + chaincodeStub.GetStateReturnsOnCall(3, bytes, nil) + chaincodeStub.GetStateReturnsOnCall(4, nil, fmt.Errorf("Failed to read state")) + bal, err = simpleToken.GetBalance(transactionContext, "", "") + require.EqualError(t, err, "failed to read owner's wallet from world state: Failed to read state") +} + +func TestGetMyWallet(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedRes := createKeyValuePairs(walletMap) + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetCreatorReturns([]byte(getCreator()), nil) + + // Successful GetBalance case + chaincodeStub.GetStateReturnsOnCall(0, bytes, nil) + bal, err := simpleToken.GetMyWallet(transactionContext) + require.NoError(t, err) + require.Equal(t, bal, expectedRes) + + chaincodeStub.GetStateReturnsOnCall(1, nil, fmt.Errorf("Failed to read state")) + bal, err = simpleToken.GetMyWallet(transactionContext) + require.EqualError(t, err, "failed to read owner's wallet from world state: Failed to read state") + + // Owner doesn't have a wallet + chaincodeStub.GetStateReturnsOnCall(2, nil, nil) + bal, err = simpleToken.GetMyWallet(transactionContext) + require.EqualError(t, err, "owner does not have a wallet") +} + +func TestTokenAssetsExist(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Token Assets exist case + chaincodeStub.GetStateReturns(bytes, nil) + res, err := simpleToken.TokenAssetsExist(transactionContext, "token1", 4) + require.NoError(t, err) + require.Equal(t, res, true) + + // Token Assets doesn't exist case + chaincodeStub.GetStateReturns(bytes, nil) + res, err = simpleToken.TokenAssetsExist(transactionContext, "token1", 6) + require.NoError(t, err) + require.Equal(t, res, false) + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("Failed to read state")) + res, err = simpleToken.TokenAssetsExist(transactionContext, "", 0) + require.EqualError(t, err, "failed to read from world state: Failed to read state") + require.Equal(t, res, false) +} + +// function that supplies value that is to be returned by ctx.GetStub().GetCreator() +func getCreator() string { + serializedIdentity := &mspProtobuf.SerializedIdentity{} + eCertBytes, _ := base64.StdEncoding.DecodeString(getTestTxCreatorECertBase64()) + serializedIdentity.IdBytes = []byte(eCertBytes) + serializedIdentity.Mspid = "ca.org1.example.com" + serializedIdentityBytes, _ := proto.Marshal(serializedIdentity) + + return string(serializedIdentityBytes) +} + +// function that supplies the ECert in base64 for the transaction creator +func getTestTxCreatorECertBase64() string { + eCertBase64 := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNVVENDQWZpZ0F3SUJBZ0lSQU5qaWdnVHRhSERGRmtIaUI3VnhPN013Q2dZSUtvWkl6ajBFQXdJd2N6RUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdUQ2tOaGJHbG1iM0p1YVdFeEZqQVVCZ05WQkFjVERWTmhiaUJHY21GdVkybHpZMjh4R1RBWEJnTlZCQW9URUc5eVp6RXVaWGhoYlhCc1pTNWpiMjB4SERBYUJnTlZCQU1URTJOaExtOXlaekV1WlhoaGJYQnNaUzVqYjIwd0hoY05NVGt3TkRBeE1EZzBOVEF3V2hjTk1qa3dNekk1TURnME5UQXdXakJ6TVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNCTUtRMkZzYVdadmNtNXBZVEVXTUJRR0ExVUVCeE1OVTJGdUlFWnlZVzVqYVhOamJ6RVpNQmNHQTFVRUNoTVFiM0puTVM1bGVHRnRjR3hsTG1OdmJURWNNQm9HQTFVRUF4TVRZMkV1YjNKbk1TNWxlR0Z0Y0d4bExtTnZiVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCT2VlYTRCNlM5ZTlyLzZUWGZFZUFmZ3FrNVdpcHZZaEdveGg1ZEZuK1g0bTN2UXZTQlhuVFdLVzczZVNnS0lzUHc5dExDVytwZW9yVnMxMWdieXdiY0dqYlRCck1BNEdBMVVkRHdFQi93UUVBd0lCcGpBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFnWUlLd1lCQlFVSEF3RXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QXBCZ05WSFE0RUlnUWcxYzJHZmJTa3hUWkxIM2VzUFd3c2llVkU1QWhZNHNPQjVGOGEvaHM5WjhVd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ1JkZ1krNW9iMDNqVjJLSzFWdjZiZE5xM2NLWHc0cHhNVXY5MFZOc0tHdTBDSUE4Q0lMa3ZEZWg3NEFCRDB6QUNkbitBTkMyVVQ2Sk5UNnd6VHNLN3BYdUwKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==" + + return eCertBase64 +} + +func createKeyValuePairs(m map[string]uint64) string { + b := new(bytes.Buffer) + for key, value := range m { + fmt.Fprintf(b, "%s=\"%d\"\n", key, value) + } + return b.String() +} diff --git a/weaver/sdks/fabric/interoperation-node-sdk/index.js b/weaver/sdks/fabric/interoperation-node-sdk/index.js index 34293f16e7..53d21b5455 100644 --- a/weaver/sdks/fabric/interoperation-node-sdk/index.js +++ b/weaver/sdks/fabric/interoperation-node-sdk/index.js @@ -15,6 +15,7 @@ module.exports.RelayHelper = require("./src/Relay.js"); module.exports.InteroperableHelper = require("./src/InteroperableHelper.js"); module.exports.AssetManager = require("./src/AssetManager.js"); +module.exports.SatpAssetManager = require("./src/SatpAssetManager.js"); module.exports.HashFunctions = require("./src/HashFunctions.js"); module.exports.EventsManager = require("./src/EventsManager.js"); module.exports.MembershipManager = require("./src/MembershipManager.js"); diff --git a/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts b/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts index d18813ecb3..772fb10e2e 100644 --- a/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts +++ b/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts @@ -393,6 +393,64 @@ const claimFungibleAssetInHTLC = async ( return result; }; +const assignAsset = async ( + contract: Contract, + assetType: string, + assetID: string, + lockerECert: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, "", lockerECert); + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("AssignAsset") + const ccArgs = [assetExchangeAgreementStr, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`AssignAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + /** * Rollback step of a Hashed Time Lock Contract * - Reclaim a unique asset instance @@ -1031,6 +1089,7 @@ export { claimAssetInHTLC, claimAssetInHTLCusingContractId, claimFungibleAssetInHTLC, + assignAsset, reclaimAssetInHTLC, reclaimAssetInHTLCusingContractId, reclaimFungibleAssetInHTLC, diff --git a/weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts b/weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts new file mode 100644 index 0000000000..313c995765 --- /dev/null +++ b/weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts @@ -0,0 +1,1111 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * This file provides helper functions for interoperability operations. + **/ +/** End file docs */ + +import log4js from "log4js"; +import crypto from "crypto"; +import fabproto6 from "fabric-protos"; +import * as helpers from "./helpers"; +import assetLocksPb from "@hyperledger/cacti-weaver-protos-js/common/asset_locks_pb"; +import { Contract, ContractListener } from "fabric-network"; +import { Hash, SHA256, SHA512 } from "./HashFunctions" +const logger = log4js.getLogger("InteroperableHelper"); + + +// Create an asset exchange agreement structure +function createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, lockerECert) +{ + const assetExchangeAgreement = new assetLocksPb.AssetExchangeAgreement(); + assetExchangeAgreement.setAssettype(assetType); + assetExchangeAgreement.setId(assetID); + assetExchangeAgreement.setRecipient(recipientECert); + assetExchangeAgreement.setLocker(lockerECert); + return Buffer.from(assetExchangeAgreement.serializeBinary()).toString('base64'); +} + +// Create a fungible asset exchange agreement structure +function createFungibleAssetExchangeAgreementSerialized(assetType, numUnits, recipientECert, lockerECert) +{ + const assetExchangeAgreement = new assetLocksPb.FungibleAssetExchangeAgreement(); + assetExchangeAgreement.setAssettype(assetType); + assetExchangeAgreement.setNumunits(numUnits); + assetExchangeAgreement.setRecipient(recipientECert); + assetExchangeAgreement.setLocker(lockerECert); + return Buffer.from(assetExchangeAgreement.serializeBinary()).toString('base64'); +} + +// Create an asset lock structure +function createAssetLockInfoSerialized(hash, expiryTimeSecs) +{ + const lockInfoHTLC = new assetLocksPb.AssetLockHTLC(); + lockInfoHTLC.setHashmechanism(hash.HASH_MECHANISM); + lockInfoHTLC.setHashbase64(Buffer.from(hash.getSerializedHashBase64())); + lockInfoHTLC.setExpirytimesecs(expiryTimeSecs); + lockInfoHTLC.setTimespec(assetLocksPb.TimeSpec.EPOCH); + const lockInfoHTLCSerialized = lockInfoHTLC.serializeBinary(); + const lockInfo = new assetLocksPb.AssetLock(); + lockInfo.setLockmechanism(assetLocksPb.LockMechanism.HTLC); + lockInfo.setLockinfo(lockInfoHTLCSerialized); + return Buffer.from(lockInfo.serializeBinary()).toString('base64'); +} + +// Create an asset claim structure +function createAssetClaimInfoSerialized(hash) +{ + const claimInfoHTLC = new assetLocksPb.AssetClaimHTLC(); + claimInfoHTLC.setHashmechanism(hash.HASH_MECHANISM); + claimInfoHTLC.setHashpreimagebase64(Buffer.from(hash.getSerializedPreimageBase64())); + const claimInfoHTLCSerialized = claimInfoHTLC.serializeBinary(); + const claimInfo = new assetLocksPb.AssetClaim(); + claimInfo.setLockmechanism(assetLocksPb.LockMechanism.HTLC); + claimInfo.setClaiminfo(claimInfoHTLCSerialized); + return Buffer.from(claimInfo.serializeBinary()).toString('base64'); +} + +/** + * First/second step of a Hashed Time Lock Contract + * - Lock a unique asset instance using a hash + * + * Byzantine Swaps: Call StartHTLCAssetLockListener within here while passing new callback + * parameter as newly defined function: assetLockExpirationCallback is passed as localCallback + **/ +const createHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + recipientECert: string, + hash: Hash, + expiryTimeSecs: number, + timeoutCallback: (c: Contract, t: string, i: string, r: string, h: Hash) => any, + endorsingOrgs: Array = [], +): Promise<{ hash: Hash; result: any }> => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return { hash: null, result: false }; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return { hash: null, result: false }; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return { hash: null, result: false }; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return { hash: null, result: false }; + } + const currTimeSecs = Math.floor(Date.now()/1000); // Convert epoch milliseconds to seconds + if (expiryTimeSecs <= currTimeSecs) + { + logger.error("Supplied expiry time invalid or in the past: %s; current time: %s", new Date(expiryTimeSecs).toISOString(), new Date(currTimeSecs).toISOString()); + return { hash: null, result: false }; + } + + if (hash == null) { + hash = new SHA256() + } + if (hash.hash64 == null) { + hash.generateRandomPreimage(22); + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, ""); + const lockInfoStr = createAssetLockInfoSerialized(hash, expiryTimeSecs); + + //If timeoutCallback is not defined, start automated listener + if (!timeoutCallback) + { + StartHTLCAssetLockListener(contract, "", assetType, assetID, recipientECert, "", assetLockExpirationCallback, endorsingOrgs); + } + + const tx = contract.createTransaction("LockAsset") + const ccArgs = [assetExchangeAgreementStr, lockInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + // Normal invoke function + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`LockAsset submitTransaction Error: ${submitError}`); + } + + if (timeoutCallback) + { + // Start timer for lock expiration + setTimeout(timeoutCallback, (expiryTimeSecs * 1000) - Date.now(), contract, assetType, assetID, recipientECert, hash); + } + + return { hash: hash, result: result }; +}; + +/** + * First/second step of a Hashed Time Lock Contract + * - Lock a set of fungible assets using a hash + **/ +const createFungibleHTLC = async ( + contract: Contract, + assetType: string, + numUnits: number, + recipientECert: string, + hash: Hash, + expiryTimeSecs: number, + timeoutCallback: (c: Contract, i: string, t: string, n: number, r: string, h: Hash) => any, + endorsingOrgs: Array = [], +): Promise<{ hash: Hash; result: any }> => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return { hash: null, result: "" }; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return { hash: null, result: "" }; + } + if (numUnits <= 0) + { + logger.error("Asset count must be a positive integer"); + return { hash: null, result: "" }; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return { hash: null, result: "" }; + } + const currTimeSecs = Math.floor(Date.now()/1000); // Convert epoch milliseconds to seconds + if (expiryTimeSecs <= currTimeSecs) + { + logger.error("Supplied expiry time invalid or in the past: %s; current time: %s", new Date(expiryTimeSecs).toISOString(), new Date(currTimeSecs).toISOString()); + return { hash: null, result: "" }; + } + + if (!hash) { + hash = new SHA256() + } + if (hash.hash64 == null) { + hash.generateRandomPreimage(22); + } + + const assetExchangeAgreementStr = createFungibleAssetExchangeAgreementSerialized(assetType, numUnits, recipientECert, ""); + const lockInfoStr = createAssetLockInfoSerialized(hash, expiryTimeSecs); + + //If timeoutCallback is not defined, start automated listener + if (!timeoutCallback) + { + StartHTLCFungibleAssetLockListener(contract, "", assetType, numUnits, recipientECert, "", fungibleAssetLockExpirationCallback, endorsingOrgs); + } + + const tx = contract.createTransaction("LockFungibleAsset") + const ccArgs = [assetExchangeAgreementStr, lockInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + // Normal invoke function + const [contractId, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`LockFungibleAsset submitTransaction Error: ${submitError}`); + } + + if (timeoutCallback) + { + // Start timer for lock expiration + setTimeout(timeoutCallback, (expiryTimeSecs * 1000) - Date.now(), contract, contractId, assetType, numUnits, recipientECert, hash); + } + + return { hash: hash, result: contractId }; +}; + +/** + * Latter step of a Hashed Time Lock Contract + * - Claim a unique asset instance using a hash preimage + **/ +const claimAssetInHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + lockerECert: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, "", lockerECert); + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("ClaimAsset") + const ccArgs = [assetExchangeAgreementStr, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`ClaimAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +const assignAsset = async ( + contract: Contract, + assetType: string, + assetID: string, + lockerECert: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, "", lockerECert); + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("AssignAsset") + const ccArgs = [assetExchangeAgreementStr, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`AssignAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Latter step of a Hashed Time Lock Contract + * - Claim a unique asset instance using a hash preimage and contractId + **/ +const claimAssetInHTLCusingContractId = async ( + contract: Contract, + contractId: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("ClaimAssetUsingContractId") + const ccArgs = [contractId, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`ClaimAssetUsingContractId submitTransaction Error: ${submitError}`); + } + return result; +}; + + +/** + * Latter step of a Hashed Time Lock Contract + * - Claim a set of fungible assets using a hash preimage + **/ +const claimFungibleAssetInHTLC = async ( + contract: Contract, + contractId: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("ClaimFungibleAsset") + const ccArgs = [contractId, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`ClaimFungibleAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Rollback step of a Hashed Time Lock Contract + * - Reclaim a unique asset instance + **/ +const reclaimAssetInHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + recipientECert: string, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, ""); + + // Normal invoke function + const tx = contract.createTransaction("UnlockAsset") + const ccArgs = [assetExchangeAgreementStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`UnlockAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Rollback step of a Hashed Time Lock Contract + * - Reclaim a unique asset instance using contractId + **/ +const reclaimAssetInHTLCusingContractId = async ( + contract: Contract, + contractId: string, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const tx = contract.createTransaction("UnlockAssetUsingContractId") + const ccArgs = [contractId] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`UnlockAssetUsingContractId submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Rollback step of a Hashed Time Lock Contract + * - Reclaim a set of fungible assets + **/ +const reclaimFungibleAssetInHTLC = async ( + contract: Contract, + contractId: string, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const tx = contract.createTransaction("UnlockFungibleAsset") + const ccArgs = [contractId] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`UnlockFungibleAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Query the state of a Hashed Time Lock Contract + * - Determine if a unique asset instance is locked by a given party for another given party + **/ +const isAssetLockedInHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + recipientECert: string, + lockerECert: string, +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, lockerECert); + + // Normal invoke function + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("IsAssetLocked", assetExchangeAgreementStr), + ); + if (evaluateError) { + throw new Error(`IsAssetLocked evaluateTransaction Error: ${evaluateError}`); + } + return result.toString() === "true"; +}; + +/** + * Query the state of a Hashed Time Lock Contract using contractId + * - Determine if a unique asset instance is locked by a given party for another given party + **/ +const isAssetLockedInHTLCqueryUsingContractId = async ( + contract: Contract, + contractId: string, +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("IsAssetLockedQueryUsingContractId", contractId), + ); + if (evaluateError) { + throw new Error(`IsAssetLockedQueryUsingContractId evaluateTransaction Error: ${evaluateError}`); + } + return result.toString() === "true"; +}; + +/** + * Query the state of a Hashed Time Lock Contract + * - Determine if a set of fungible assets is locked by a given party for another given party + **/ +const isFungibleAssetLockedInHTLC = async ( + contract: Contract, + contractId: string, +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("IsFungibleAssetLocked", contractId), + ); + if (evaluateError) { + throw new Error(`IsFungibleAssetLocked evaluateTransaction Error: ${evaluateError}`); + } + return result.toString() === "true"; +}; + + +/** + * HTLC Lifecycle Events + * - Developers should note that event emission and actions in response occur on a best effort basis. + * - Also, there is no guarantee that a particular event (lock, claim, reclaim) will ever get emitted + * - Therefore, the calling (or listening) logic should incorporate suitable fallbacks and timeouts. + **/ + +/** + * The below functions trigger callbacks passed as arguments when a matching event is received from the contract layer + **/ +const StartHTLCEventListener = ( + contract: Contract, + eventName: string, + contractId: string, + assetType: string, + assetId: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + eventCallback: Function, + endorsingOrgs: Array = [], +): void => { + const listener: ContractListener = async (event) => { + if (event.eventName === eventName) { + let assetLockContractInfo; + + if (eventName.includes('Fungible')) { + const eventInfo: assetLocksPb.FungibleAssetContractHTLC = assetLocksPb.FungibleAssetContractHTLC.deserializeBinary(event.payload); + assetLockContractInfo = eventInfo; + } + else { + const eventInfo: assetLocksPb.AssetContractHTLC = assetLocksPb.AssetContractHTLC.deserializeBinary(event.payload); + assetLockContractInfo = eventInfo; + } + const infoContractId = assetLockContractInfo.getContractid(); + if (contractId && contractId.length > 0) { + if (infoContractId.length > 0 && infoContractId !== contractId) { + return; + } + } + const infoAssetType = assetLockContractInfo.getAgreement().getAssettype(); + if (assetType && assetType.length > 0) { + if (infoAssetType.length > 0 && infoAssetType !== assetType) { + return; + } + } + let infoNumUnits: number, infoAssetId: string; + if (eventName.includes('Fungible')) { + infoNumUnits = assetLockContractInfo.getAgreement().getNumunits(); + if (infoNumUnits != numUnits) { + return; + } + } + else { + infoAssetId = assetLockContractInfo.getAgreement().getId(); + if (assetId && assetId.length > 0) { + if (infoAssetId.length > 0 && infoAssetId !== assetId) { + return; + } + } + } + const infoRecipient = assetLockContractInfo.getAgreement().getRecipient(); + if (recipientECert && recipientECert.length > 0) { + if (infoRecipient.length > 0 && infoRecipient !== recipientECert) { + return; + } + } + const infoLocker = assetLockContractInfo.getAgreement().getLocker(); + if (lockerECert && lockerECert.length > 0) { + if (infoLocker.length > 0 && infoLocker !== lockerECert) { + return; + } + } + // All filters passed + if (eventName === 'LockAsset' || eventName === 'LockFungibleAsset') { + const timeout = assetLockContractInfo.getLock().getExpirytimesecs(); + const hashBase64 = assetLockContractInfo.getLock().getHashbase64(); + let hash: Hash; + + const hashMechanism = assetLockContractInfo.getLock().getHashmechanism(); + if (hashMechanism === assetLocksPb.HashMechanism.SHA256) { + hash = new SHA256(); + } + else if (hashMechanism === assetLocksPb.HashMechanism.SHA512) { + hash = new SHA512(); + } + else { + throw new Error(`Hash Mechanism not supported`); + } + hash.setSerializedHashBase64(hashBase64); + // We only care about timeouts for locking the asset, not for the unlock itself + if (eventName === 'LockAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoAssetId, infoRecipient, infoLocker, hash, timeout, endorsingOrgs); + } + else { + eventCallback(contract, infoContractId, infoAssetType, infoNumUnits, infoRecipient, infoLocker, hash, timeout, endorsingOrgs); + } + } else if (eventName === 'ClaimAsset' || eventName === 'ClaimFungibleAsset') { + const hashPreimageBase64 = assetLockContractInfo.getClaim().getHashpreimagebase64(); + const hashPreimage: string = Buffer.from(hashPreimageBase64.toString(), 'base64').toString('utf8'); + if (eventName === 'ClaimAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoAssetId, infoRecipient, infoLocker, hashPreimage); + } + else { + eventCallback(contract, infoContractId, infoAssetType, infoNumUnits, infoRecipient, infoLocker, hashPreimage); + } + } + else if (eventName === 'UnlockAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoAssetId, infoRecipient, infoLocker); + } + else if (eventName === 'UnlockFungibleAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoNumUnits, infoRecipient, infoLocker); + } + } + }; + contract.addContractListener(listener); +} + +const StartHTLCAssetLockListener = ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, + lockCallback: (c: Contract, d: string, t: string, i: string, r: string, l: string, v: Hash, timeout: number, eOrgs: Array) => any, + endorsingOrgs: Array = [], +): void => { + StartHTLCEventListener(contract, 'LockAsset', contractId, assetType, assetId, -1, recipientECert, lockerECert, lockCallback, endorsingOrgs); +} + +// NOTE: For Nonfungible Assets +// Byzantine Swaps: Timed counterpart for timed AssetLockListener for reversion +const assetLockExpirationCallback = ( + contract: Contract, + contractID: string, + assetType: string, + assetID: string, + recipientECert: string, + lockerECert: string, + hash: Hash, + expiryTime: number, + endorsingOrgs: Array = [] +): void => { + // Compare expiryTimeSec with currentTimeSec, which is number of milliseconds since epoch (L174) + const currTimeSecs = Math.floor(Date.now()/1000); + const reclaimCallback = async (contract: Contract, contractID: string) => { + // Check if asset hasn't been claimed yet. If true, do nothing. If false, either do the following cases: + const [islocked, isLockedQueryError] = await helpers.handlePromise(isAssetLockedInHTLCqueryUsingContractId(contract, contractID)); + if (islocked === false) { + // CASE #1: Check GetHTLCHashPreImageByContractId(contractId) + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("GetHTLCHashPreImageByContractId", contractID), + ); + + // CASE #2: If the function above returns ANY error, call reclaimAssetInHTLC + if (evaluateError) { + // Put retry logic in event of failure. Retry 3x and then give up if unsuccessful (temp solution for now; requires CORE changes) + // If it fails, retry for i (arbitrarily defined) more attempts until you quit + let i = 0; + do { + let [retryReclaimResult, retryReclaimableQueryError] = await helpers.handlePromise(reclaimAssetInHTLCusingContractId(contract, contractID, endorsingOrgs)); + if (!retryReclaimableQueryError) { + console.log("Nonfungible Asset unlocked successfully"); + break; + } + + i++; + } while (i < 3); + } + } + } + + // If you have time remaining, call setTimeout with reclaimCallback + if (expiryTime - currTimeSecs > 0) { + setTimeout(reclaimCallback, 1000 * (expiryTime - currTimeSecs), contract, contractID); + } else { + // If no time remaining, call the reclaim callback immediately + reclaimCallback(contract, contractID); + } +} + +//NOTE: FUNGIBLE counterpart +// Byzantine Swaps: Timed counterpart for timed AssetLockListener for reversion +const fungibleAssetLockExpirationCallback = ( + contract: Contract, + contractID: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + hash: Hash, + expiryTime: number, + endorsingOrgs: Array = [] +): void => { + // Compare expiryTimeSec with currentTimeSec, which is number of milliseconds since epoch (L174) + const currTimeSecs = Math.floor(Date.now()/1000); + const reclaimCallback = async (contract: Contract, contractID: string) => { + // Check if asset hasn't been claimed yet. If true, do nothing. If false, either do the following cases: + const [islocked, isLockedQueryError] = await helpers.handlePromise(isFungibleAssetLockedInHTLC(contract, contractID)); + + if (islocked === false) { + // CASE #1: Check GetHTLCHashPreImageByContractId(contractId) + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("GetHTLCHashPreImageByContractId", contractID), + ); + + // CASE #2: If the function above returns ANY error, call reclaimAssetInHTLC + if (evaluateError) { + // Put retry logic in event of failure. Retry 3x and then give up if unsuccessful (temp solution for now; requires CORE changes) + // If it fails, retry for i (arbitrarily defined) more attempts until you quit + let i = 0; + do { + let [retryReclaimResult, retryReclaimableQueryError] = await helpers.handlePromise(reclaimFungibleAssetInHTLC(contract, contractID, endorsingOrgs)); + if (!retryReclaimableQueryError) { + console.log("Fungible Asset unlocked successfully"); + break; + } + + i++; + } while (i < 3); + } + } + } + + // If you have time remaining, call setTimeout with reclaimCallback + if (expiryTime - currTimeSecs > 0) { + setTimeout(reclaimCallback, 1000 * (expiryTime - currTimeSecs), contract, contractID); + } else { + // If no time remaining, call the reclaim callback immediately + reclaimCallback(contract, contractID); + } +} + +const StartHTLCAssetClaimListener = ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, + claimCallback: (c: Contract, d: string, t: string, i: string, r: string, l: string, p: string) => any, +): void => { + StartHTLCEventListener(contract, 'ClaimAsset', contractId, assetType, assetId, -1, recipientECert, lockerECert, claimCallback); +} + +const StartHTLCAssetUnlockListener = ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, + unlockCallback: (c: Contract, d: string, t: string, i: string, r: string, l: string) => any, +): void => { + StartHTLCEventListener(contract, 'UnlockAsset', contractId, assetType, assetId, -1, recipientECert, lockerECert, unlockCallback); +} + +const StartHTLCFungibleAssetLockListener = ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + lockCallback: (c: Contract, d: string, t: string, n: number, r: string, l: string, v: Hash, timeout: number, eOrgs: Array) => any, + endorsingOrgs: Array = [], +): void => { + StartHTLCEventListener(contract, 'LockFungibleAsset', contractId, assetType, "", numUnits, recipientECert, lockerECert, lockCallback, endorsingOrgs); +} + +const StartHTLCFungibleAssetClaimListener = ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + claimCallback: (c: Contract, d: string, t: string, n: number, r: string, l: string, p: string) => any, +): void => { + StartHTLCEventListener(contract, 'ClaimFungibleAsset', contractId, assetType, "", numUnits, recipientECert, lockerECert, claimCallback); +} + +const StartHTLCFungibleAssetUnlockListener = ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + unlockCallback: (c: Contract, d: string, t: string, n: number, r: string, l: string) => any, +): void => { + StartHTLCEventListener(contract, 'UnlockFungibleAsset', contractId, assetType, "", numUnits, recipientECert, lockerECert, unlockCallback); +} + +/** + * The below functions return promises for HTLC events. + * Developers can use 'await' to synchronously manage asset swapping logic. + **/ + const HTLCAssetLocked = async ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForLock = (contract, contractId, assetType, assetId, recipientECert, lockerECert, hashValue) => { + resolve(hashValue); + }; + StartHTLCAssetLockListener(contract, contractId, assetType, assetId, recipientECert, lockerECert, waitForLock); + }); +} + +const HTLCAssetClaimed = async ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForClaim = (contract, contractId, assetType, assetId, recipientECert, lockerECert, hashPreimage) => { + resolve(hashPreimage); + }; + StartHTLCAssetClaimListener(contract, contractId, assetType, assetId, recipientECert, lockerECert, waitForClaim); + }); +} + +const HTLCAssetUnlocked = async ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForUnlock = (contract, contractId, assetType, assetId, recipientECert, lockerECert) => { + resolve(); + }; + StartHTLCAssetUnlockListener(contract, contractId, assetType, assetId, recipientECert, lockerECert, waitForUnlock); + }); +} + +const HTLCFungibleAssetLocked = async ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForLock = (contract, contractId, assetType, numUnits, recipientECert, lockerECert, hashValue) => { + resolve(hashValue); + }; + StartHTLCFungibleAssetLockListener(contract, contractId, assetType, numUnits, recipientECert, lockerECert, waitForLock); + }); +} + +const HTLCFungibleAssetClaimed = async ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForClaim = (contract, contractId, assetType, numUnits, recipientECert, lockerECert, hashPreimage) => { + resolve(hashPreimage); + }; + StartHTLCFungibleAssetClaimListener(contract, contractId, assetType, numUnits, recipientECert, lockerECert, waitForClaim); + }); +} + +const HTLCFungibleAssetUnlocked = async ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForUnlock = (contract, contractId, assetType, numUnits, recipientECert, lockerECert) => { + resolve(); + }; + StartHTLCFungibleAssetUnlockListener(contract, contractId, assetType, numUnits, recipientECert, lockerECert, waitForUnlock); + }); +} + +export { + createAssetExchangeAgreementSerialized, + createFungibleAssetExchangeAgreementSerialized, + createAssetLockInfoSerialized, + createAssetClaimInfoSerialized, + createHTLC, + createFungibleHTLC, + claimAssetInHTLC, + claimAssetInHTLCusingContractId, + claimFungibleAssetInHTLC, + reclaimAssetInHTLC, + reclaimAssetInHTLCusingContractId, + reclaimFungibleAssetInHTLC, + assignAsset, + isAssetLockedInHTLC, + isAssetLockedInHTLCqueryUsingContractId, + isFungibleAssetLockedInHTLC, + StartHTLCAssetLockListener, + StartHTLCAssetClaimListener, + StartHTLCAssetUnlockListener, + StartHTLCFungibleAssetLockListener, + StartHTLCFungibleAssetClaimListener, + StartHTLCFungibleAssetUnlockListener, + HTLCAssetLocked, + HTLCAssetClaimed, + HTLCAssetUnlocked, + HTLCFungibleAssetLocked, + HTLCFungibleAssetClaimed, + HTLCFungibleAssetUnlocked, +}; diff --git a/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts b/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts index 4ec78c0f11..f965212e3e 100644 --- a/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts +++ b/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts @@ -14,6 +14,8 @@ import * as RelayHelper from "../src/Relay"; export { RelayHelper }; import * as AssetManager from "../src/AssetManager"; export { AssetManager }; +import * as SatpAssetManager from "../src/SatpAssetManager"; +export { SatpAssetManager }; import * as HashFunctions from "../src/HashFunctions"; export { HashFunctions }; import * as EventsManager from "../src/EventsManager"; diff --git a/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh b/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh index fd16f38531..6daf76491d 100755 --- a/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh +++ b/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh @@ -302,6 +302,10 @@ chaincodeInvokeInit() { peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Bond", "interop"]}' >&log.txt elif [ "$CC_CHAIN_CODE" = "simpleasset" ] && [ "$NW_NAME" = "network2" ]; then peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Token", "interop"]}' >&log.txt + elif [ "$CC_CHAIN_CODE" = "satpsimpleasset" ] && [ "$NW_NAME" = "network1" ]; then + peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Bond", "interop"]}' >&log.txt + elif [ "$CC_CHAIN_CODE" = "satpsimpleasset" ] && [ "$NW_NAME" = "network2" ]; then + peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Token", "interop"]}' >&log.txt elif [ "$CC_CHAIN_CODE" = "simpleassettransfer" ] && [ "$NW_NAME" = "network1" ]; then peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["interop", "network1"]}' >&log.txt elif [ "$CC_CHAIN_CODE" = "simpleassettransfer" ] && [ "$NW_NAME" = "network2" ]; then From 440c140fc9f79317c9ab1fb51be70f6c3db84d2f Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 12 Sep 2023 08:23:19 +0100 Subject: [PATCH 39/59] uncommented the perform lock part --- .../core/drivers/fabric-driver/server/satp.ts | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index 0f0eef77b5..a1c6c6ca1c 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -104,17 +104,17 @@ async function performLockHelper( console.info(`Asset Lock: Lock ${asset}:\n`); try { console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) - // const res = await funcToCall(network.contract, - // params[0], - // params[1], - // recipientCert, - // hash, - // timeout, - // null) - // if (!res.result) { - // throw new Error() - // } - // console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) + const res = await funcToCall(network.contract, + params[0], + params[1], + recipientCert, + hash, + timeout, + null) + if (!res.result) { + throw new Error() + } + console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) console.info('Asset has been locked successfully') } catch (error) { @@ -144,7 +144,7 @@ async function createAssetHelper( createAssetRequest2['owner'] = 'admin'; createAssetRequest2['type'] = 'bond'; createAssetRequest2['assetType'] = 'bond01'; - createAssetRequest2['id'] = 'a065'; + createAssetRequest2['id'] = 'a0demo'; createAssetRequest2['issuer'] = 'admin'; createAssetRequest2['facevalue'] = '300'; createAssetRequest2['maturitydate'] = '05 May 48 00:00 MST'; @@ -254,7 +254,7 @@ async function assignAssetHelper( assignAssetRequest2['contract-id'] = 'abc01'; assignAssetRequest2['hash_fn'] = ''; assignAssetRequest2['secret'] = 'secrettext'; - assignAssetRequest2['param'] = 'bond01:a065'; + assignAssetRequest2['param'] = 'bond01:a0demo'; const targetNetwork = assignAssetRequest2['target-network']; const locker = assignAssetRequest2['locker']; From 0ed12e955d4265e0818f380587184eed8a866872 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 19 Sep 2023 14:30:00 +0100 Subject: [PATCH 40/59] corrected compile error due to merging issue --- .../protos-go/common/access_control.pb.go | 6 +- weaver/common/protos-go/common/ack.pb.go | 6 +- .../common/protos-go/common/asset_locks.pb.go | 6 +- .../protos-go/common/asset_transfer.pb.go | 6 +- weaver/common/protos-go/common/events.pb.go | 6 +- .../protos-go/common/interop_payload.pb.go | 6 +- .../common/protos-go/common/membership.pb.go | 6 +- weaver/common/protos-go/common/proofs.pb.go | 6 +- weaver/common/protos-go/common/query.pb.go | 6 +- weaver/common/protos-go/common/state.pb.go | 6 +- .../common/verification_policy.pb.go | 6 +- weaver/common/protos-go/corda/view_data.pb.go | 6 +- weaver/common/protos-go/driver/driver.pb.go | 386 +++++++++++++++--- .../common/protos-go/driver/driver_grpc.pb.go | 170 +++++++- .../common/protos-go/fabric/view_data.pb.go | 6 +- weaver/common/protos-go/identity/agent.pb.go | 6 +- .../protos-go/identity/agent_grpc.pb.go | 6 +- .../common/protos-go/networks/networks.pb.go | 298 ++++++++++---- .../protos-go/networks/networks_grpc.pb.go | 47 ++- .../protos-rs/pkg/src/generated/common.ack.rs | 4 - .../pkg/src/generated/common.events.rs | 4 - .../pkg/src/generated/common.query.rs | 4 - .../pkg/src/generated/common.state.rs | 4 - .../pkg/src/generated/driver.driver.rs | 4 - .../pkg/src/generated/networks.networks.rs | 4 - .../pkg/src/generated/relay.datatransfer.rs | 4 - .../pkg/src/generated/relay.events.rs | 4 - weaver/core/relay/src/services/helpers.rs | 3 + weaver/samples/fabric/satpsimpleasset/go.mod | 2 +- weaver/samples/fabric/satpsimpleasset/go.sum | 8 - 30 files changed, 855 insertions(+), 181 deletions(-) diff --git a/weaver/common/protos-go/common/access_control.pb.go b/weaver/common/protos-go/common/access_control.pb.go index 7e2383c003..266a1c203d 100644 --- a/weaver/common/protos-go/common/access_control.pb.go +++ b/weaver/common/protos-go/common/access_control.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/access_control.proto package common diff --git a/weaver/common/protos-go/common/ack.pb.go b/weaver/common/protos-go/common/ack.pb.go index 4d2fcb76b6..0b97f2fa93 100644 --- a/weaver/common/protos-go/common/ack.pb.go +++ b/weaver/common/protos-go/common/ack.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/ack.proto package common diff --git a/weaver/common/protos-go/common/asset_locks.pb.go b/weaver/common/protos-go/common/asset_locks.pb.go index eebb5939ab..d844467dc6 100644 --- a/weaver/common/protos-go/common/asset_locks.pb.go +++ b/weaver/common/protos-go/common/asset_locks.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/asset_locks.proto package common diff --git a/weaver/common/protos-go/common/asset_transfer.pb.go b/weaver/common/protos-go/common/asset_transfer.pb.go index de8b050302..1e930e39b0 100644 --- a/weaver/common/protos-go/common/asset_transfer.pb.go +++ b/weaver/common/protos-go/common/asset_transfer.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/asset_transfer.proto package common diff --git a/weaver/common/protos-go/common/events.pb.go b/weaver/common/protos-go/common/events.pb.go index 06eb16548e..da4ced1927 100644 --- a/weaver/common/protos-go/common/events.pb.go +++ b/weaver/common/protos-go/common/events.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/events.proto package common diff --git a/weaver/common/protos-go/common/interop_payload.pb.go b/weaver/common/protos-go/common/interop_payload.pb.go index 0f17f37359..0a1d3c5492 100644 --- a/weaver/common/protos-go/common/interop_payload.pb.go +++ b/weaver/common/protos-go/common/interop_payload.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/interop_payload.proto package common diff --git a/weaver/common/protos-go/common/membership.pb.go b/weaver/common/protos-go/common/membership.pb.go index d851d53dbf..124f30a1a2 100644 --- a/weaver/common/protos-go/common/membership.pb.go +++ b/weaver/common/protos-go/common/membership.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/membership.proto package common diff --git a/weaver/common/protos-go/common/proofs.pb.go b/weaver/common/protos-go/common/proofs.pb.go index 9c225d199c..5611cd3ee5 100644 --- a/weaver/common/protos-go/common/proofs.pb.go +++ b/weaver/common/protos-go/common/proofs.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/proofs.proto package common diff --git a/weaver/common/protos-go/common/query.pb.go b/weaver/common/protos-go/common/query.pb.go index f4b9f17bed..e66e708342 100644 --- a/weaver/common/protos-go/common/query.pb.go +++ b/weaver/common/protos-go/common/query.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/query.proto package common diff --git a/weaver/common/protos-go/common/state.pb.go b/weaver/common/protos-go/common/state.pb.go index fa68086ea5..30d8c72c85 100644 --- a/weaver/common/protos-go/common/state.pb.go +++ b/weaver/common/protos-go/common/state.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/state.proto package common diff --git a/weaver/common/protos-go/common/verification_policy.pb.go b/weaver/common/protos-go/common/verification_policy.pb.go index 26d80f9158..bbdac635f4 100644 --- a/weaver/common/protos-go/common/verification_policy.pb.go +++ b/weaver/common/protos-go/common/verification_policy.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/verification_policy.proto package common diff --git a/weaver/common/protos-go/corda/view_data.pb.go b/weaver/common/protos-go/corda/view_data.pb.go index 37f9bd8b6a..720eca12ac 100644 --- a/weaver/common/protos-go/corda/view_data.pb.go +++ b/weaver/common/protos-go/corda/view_data.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: corda/view_data.proto package corda diff --git a/weaver/common/protos-go/driver/driver.pb.go b/weaver/common/protos-go/driver/driver.pb.go index 764501f673..5ed253b931 100644 --- a/weaver/common/protos-go/driver/driver.pb.go +++ b/weaver/common/protos-go/driver/driver.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: driver/driver.proto package driver @@ -77,6 +81,194 @@ func (x *WriteExternalStateMessage) GetCtx() *common.ContractTransaction { return nil } +type PerformLockRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` +} + +func (x *PerformLockRequest) Reset() { + *x = PerformLockRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_driver_driver_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PerformLockRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PerformLockRequest) ProtoMessage() {} + +func (x *PerformLockRequest) ProtoReflect() protoreflect.Message { + mi := &file_driver_driver_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PerformLockRequest.ProtoReflect.Descriptor instead. +func (*PerformLockRequest) Descriptor() ([]byte, []int) { + return file_driver_driver_proto_rawDescGZIP(), []int{1} +} + +func (x *PerformLockRequest) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +type CreateAssetRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` +} + +func (x *CreateAssetRequest) Reset() { + *x = CreateAssetRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_driver_driver_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateAssetRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAssetRequest) ProtoMessage() {} + +func (x *CreateAssetRequest) ProtoReflect() protoreflect.Message { + mi := &file_driver_driver_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAssetRequest.ProtoReflect.Descriptor instead. +func (*CreateAssetRequest) Descriptor() ([]byte, []int) { + return file_driver_driver_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateAssetRequest) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +type ExtinguishRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` +} + +func (x *ExtinguishRequest) Reset() { + *x = ExtinguishRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_driver_driver_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExtinguishRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExtinguishRequest) ProtoMessage() {} + +func (x *ExtinguishRequest) ProtoReflect() protoreflect.Message { + mi := &file_driver_driver_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExtinguishRequest.ProtoReflect.Descriptor instead. +func (*ExtinguishRequest) Descriptor() ([]byte, []int) { + return file_driver_driver_proto_rawDescGZIP(), []int{3} +} + +func (x *ExtinguishRequest) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +type AssignAssetRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` +} + +func (x *AssignAssetRequest) Reset() { + *x = AssignAssetRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_driver_driver_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AssignAssetRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AssignAssetRequest) ProtoMessage() {} + +func (x *AssignAssetRequest) ProtoReflect() protoreflect.Message { + mi := &file_driver_driver_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AssignAssetRequest.ProtoReflect.Descriptor instead. +func (*AssignAssetRequest) Descriptor() ([]byte, []int) { + return file_driver_driver_proto_rawDescGZIP(), []int{4} +} + +func (x *AssignAssetRequest) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + var File_driver_driver_proto protoreflect.FileDescriptor var file_driver_driver_proto_rawDesc = []byte{ @@ -96,36 +288,66 @@ var file_driver_driver_proto_rawDesc = []byte{ 0x34, 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x03, 0x63, 0x74, 0x78, 0x32, 0xcd, 0x02, 0x0a, 0x13, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, - 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, - 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0e, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, + 0x52, 0x03, 0x63, 0x74, 0x78, 0x22, 0x33, 0x0a, 0x12, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, + 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x33, 0x0a, 0x12, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, + 0x32, 0x0a, 0x11, 0x45, 0x78, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x22, 0x33, 0x0a, 0x12, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x32, 0xdf, 0x04, 0x0a, 0x13, 0x44, 0x72, 0x69, + 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x3c, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, + 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x45, + 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x23, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x20, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x13, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x12, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x2e, 0x64, 0x72, + 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x57, 0x72, 0x69, 0x74, + 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, + 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x66, + 0x6f, 0x72, 0x6d, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x21, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, + 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x4c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x43, 0x0a, + 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x21, 0x2e, 0x64, + 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, - 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x23, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x69, 0x67, - 0x6e, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x13, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x22, 0x00, 0x12, 0x51, 0x0a, 0x12, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, - 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x78, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, - 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x73, 0x0a, 0x31, 0x6f, 0x72, 0x67, 0x2e, 0x68, 0x79, 0x70, - 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x63, 0x74, 0x69, 0x2e, 0x77, - 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x64, 0x72, 0x69, - 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, - 0x65, 0x72, 0x2f, 0x63, 0x61, 0x63, 0x74, 0x69, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2f, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, - 0x2f, 0x76, 0x32, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0a, 0x45, 0x78, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, + 0x12, 0x20, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, + 0x2e, 0x45, 0x78, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0b, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x12, 0x21, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, + 0x69, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x73, 0x0a, 0x31, 0x6f, 0x72, + 0x67, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2e, 0x63, 0x61, + 0x63, 0x74, 0x69, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x73, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5a, + 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, + 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2f, 0x63, 0x61, 0x63, 0x74, 0x69, 0x2f, 0x77, 0x65, + 0x61, 0x76, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -140,31 +362,43 @@ func file_driver_driver_proto_rawDescGZIP() []byte { return file_driver_driver_proto_rawDescData } -var file_driver_driver_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_driver_driver_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_driver_driver_proto_goTypes = []interface{}{ (*WriteExternalStateMessage)(nil), // 0: driver.driver.WriteExternalStateMessage - (*common.ViewPayload)(nil), // 1: common.state.ViewPayload - (*common.ContractTransaction)(nil), // 2: common.events.ContractTransaction - (*common.Query)(nil), // 3: common.query.Query - (*common.EventSubscription)(nil), // 4: common.events.EventSubscription - (*common.Ack)(nil), // 5: common.ack.Ack + (*PerformLockRequest)(nil), // 1: driver.driver.PerformLockRequest + (*CreateAssetRequest)(nil), // 2: driver.driver.CreateAssetRequest + (*ExtinguishRequest)(nil), // 3: driver.driver.ExtinguishRequest + (*AssignAssetRequest)(nil), // 4: driver.driver.AssignAssetRequest + (*common.ViewPayload)(nil), // 5: common.state.ViewPayload + (*common.ContractTransaction)(nil), // 6: common.events.ContractTransaction + (*common.Query)(nil), // 7: common.query.Query + (*common.EventSubscription)(nil), // 8: common.events.EventSubscription + (*common.Ack)(nil), // 9: common.ack.Ack } var file_driver_driver_proto_depIdxs = []int32{ - 1, // 0: driver.driver.WriteExternalStateMessage.view_payload:type_name -> common.state.ViewPayload - 2, // 1: driver.driver.WriteExternalStateMessage.ctx:type_name -> common.events.ContractTransaction - 3, // 2: driver.driver.DriverCommunication.RequestDriverState:input_type -> common.query.Query - 4, // 3: driver.driver.DriverCommunication.SubscribeEvent:input_type -> common.events.EventSubscription - 4, // 4: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:input_type -> common.events.EventSubscription - 0, // 5: driver.driver.DriverCommunication.WriteExternalState:input_type -> driver.driver.WriteExternalStateMessage - 5, // 6: driver.driver.DriverCommunication.RequestDriverState:output_type -> common.ack.Ack - 5, // 7: driver.driver.DriverCommunication.SubscribeEvent:output_type -> common.ack.Ack - 3, // 8: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:output_type -> common.query.Query - 5, // 9: driver.driver.DriverCommunication.WriteExternalState:output_type -> common.ack.Ack - 6, // [6:10] is the sub-list for method output_type - 2, // [2:6] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 5, // 0: driver.driver.WriteExternalStateMessage.view_payload:type_name -> common.state.ViewPayload + 6, // 1: driver.driver.WriteExternalStateMessage.ctx:type_name -> common.events.ContractTransaction + 7, // 2: driver.driver.DriverCommunication.RequestDriverState:input_type -> common.query.Query + 8, // 3: driver.driver.DriverCommunication.SubscribeEvent:input_type -> common.events.EventSubscription + 8, // 4: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:input_type -> common.events.EventSubscription + 0, // 5: driver.driver.DriverCommunication.WriteExternalState:input_type -> driver.driver.WriteExternalStateMessage + 1, // 6: driver.driver.DriverCommunication.PerformLock:input_type -> driver.driver.PerformLockRequest + 2, // 7: driver.driver.DriverCommunication.CreateAsset:input_type -> driver.driver.CreateAssetRequest + 3, // 8: driver.driver.DriverCommunication.Extinguish:input_type -> driver.driver.ExtinguishRequest + 4, // 9: driver.driver.DriverCommunication.AssignAsset:input_type -> driver.driver.AssignAssetRequest + 9, // 10: driver.driver.DriverCommunication.RequestDriverState:output_type -> common.ack.Ack + 9, // 11: driver.driver.DriverCommunication.SubscribeEvent:output_type -> common.ack.Ack + 7, // 12: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:output_type -> common.query.Query + 9, // 13: driver.driver.DriverCommunication.WriteExternalState:output_type -> common.ack.Ack + 9, // 14: driver.driver.DriverCommunication.PerformLock:output_type -> common.ack.Ack + 9, // 15: driver.driver.DriverCommunication.CreateAsset:output_type -> common.ack.Ack + 9, // 16: driver.driver.DriverCommunication.Extinguish:output_type -> common.ack.Ack + 9, // 17: driver.driver.DriverCommunication.AssignAsset:output_type -> common.ack.Ack + 10, // [10:18] is the sub-list for method output_type + 2, // [2:10] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_driver_driver_proto_init() } @@ -185,6 +419,54 @@ func file_driver_driver_proto_init() { return nil } } + file_driver_driver_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PerformLockRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_driver_driver_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateAssetRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_driver_driver_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExtinguishRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_driver_driver_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AssignAssetRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -192,7 +474,7 @@ func file_driver_driver_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_driver_driver_proto_rawDesc, NumEnums: 0, - NumMessages: 1, + NumMessages: 5, NumExtensions: 0, NumServices: 1, }, diff --git a/weaver/common/protos-go/driver/driver_grpc.pb.go b/weaver/common/protos-go/driver/driver_grpc.pb.go index 08d8741e82..ce978ce6f6 100644 --- a/weaver/common/protos-go/driver/driver_grpc.pb.go +++ b/weaver/common/protos-go/driver/driver_grpc.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.17.3 +// - protoc v3.12.4 // source: driver/driver.proto package driver @@ -24,6 +28,10 @@ const ( DriverCommunication_SubscribeEvent_FullMethodName = "/driver.driver.DriverCommunication/SubscribeEvent" DriverCommunication_RequestSignedEventSubscriptionQuery_FullMethodName = "/driver.driver.DriverCommunication/RequestSignedEventSubscriptionQuery" DriverCommunication_WriteExternalState_FullMethodName = "/driver.driver.DriverCommunication/WriteExternalState" + DriverCommunication_PerformLock_FullMethodName = "/driver.driver.DriverCommunication/PerformLock" + DriverCommunication_CreateAsset_FullMethodName = "/driver.driver.DriverCommunication/CreateAsset" + DriverCommunication_Extinguish_FullMethodName = "/driver.driver.DriverCommunication/Extinguish" + DriverCommunication_AssignAsset_FullMethodName = "/driver.driver.DriverCommunication/AssignAsset" ) // DriverCommunicationClient is the client API for DriverCommunication service. @@ -44,6 +52,18 @@ type DriverCommunicationClient interface { // Events Publication // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger WriteExternalState(ctx context.Context, in *WriteExternalStateMessage, opts ...grpc.CallOption) (*common.Ack, error) + // As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver + // to lock a specific asset + PerformLock(ctx context.Context, in *PerformLockRequest, opts ...grpc.CallOption) (*common.Ack, error) + // As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + // to create a specific asset + CreateAsset(ctx context.Context, in *CreateAssetRequest, opts ...grpc.CallOption) (*common.Ack, error) + // As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + // to extinguish a specific asset + Extinguish(ctx context.Context, in *ExtinguishRequest, opts ...grpc.CallOption) (*common.Ack, error) + // As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + // to assign a specific asset + AssignAsset(ctx context.Context, in *AssignAssetRequest, opts ...grpc.CallOption) (*common.Ack, error) } type driverCommunicationClient struct { @@ -90,6 +110,42 @@ func (c *driverCommunicationClient) WriteExternalState(ctx context.Context, in * return out, nil } +func (c *driverCommunicationClient) PerformLock(ctx context.Context, in *PerformLockRequest, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, DriverCommunication_PerformLock_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *driverCommunicationClient) CreateAsset(ctx context.Context, in *CreateAssetRequest, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, DriverCommunication_CreateAsset_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *driverCommunicationClient) Extinguish(ctx context.Context, in *ExtinguishRequest, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, DriverCommunication_Extinguish_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *driverCommunicationClient) AssignAsset(ctx context.Context, in *AssignAssetRequest, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, DriverCommunication_AssignAsset_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DriverCommunicationServer is the server API for DriverCommunication service. // All implementations must embed UnimplementedDriverCommunicationServer // for forward compatibility @@ -108,6 +164,18 @@ type DriverCommunicationServer interface { // Events Publication // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger WriteExternalState(context.Context, *WriteExternalStateMessage) (*common.Ack, error) + // As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver + // to lock a specific asset + PerformLock(context.Context, *PerformLockRequest) (*common.Ack, error) + // As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + // to create a specific asset + CreateAsset(context.Context, *CreateAssetRequest) (*common.Ack, error) + // As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + // to extinguish a specific asset + Extinguish(context.Context, *ExtinguishRequest) (*common.Ack, error) + // As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + // to assign a specific asset + AssignAsset(context.Context, *AssignAssetRequest) (*common.Ack, error) mustEmbedUnimplementedDriverCommunicationServer() } @@ -127,6 +195,18 @@ func (UnimplementedDriverCommunicationServer) RequestSignedEventSubscriptionQuer func (UnimplementedDriverCommunicationServer) WriteExternalState(context.Context, *WriteExternalStateMessage) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method WriteExternalState not implemented") } +func (UnimplementedDriverCommunicationServer) PerformLock(context.Context, *PerformLockRequest) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method PerformLock not implemented") +} +func (UnimplementedDriverCommunicationServer) CreateAsset(context.Context, *CreateAssetRequest) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateAsset not implemented") +} +func (UnimplementedDriverCommunicationServer) Extinguish(context.Context, *ExtinguishRequest) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method Extinguish not implemented") +} +func (UnimplementedDriverCommunicationServer) AssignAsset(context.Context, *AssignAssetRequest) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method AssignAsset not implemented") +} func (UnimplementedDriverCommunicationServer) mustEmbedUnimplementedDriverCommunicationServer() {} // UnsafeDriverCommunicationServer may be embedded to opt out of forward compatibility for this service. @@ -212,6 +292,78 @@ func _DriverCommunication_WriteExternalState_Handler(srv interface{}, ctx contex return interceptor(ctx, in, info, handler) } +func _DriverCommunication_PerformLock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PerformLockRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverCommunicationServer).PerformLock(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DriverCommunication_PerformLock_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverCommunicationServer).PerformLock(ctx, req.(*PerformLockRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DriverCommunication_CreateAsset_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateAssetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverCommunicationServer).CreateAsset(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DriverCommunication_CreateAsset_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverCommunicationServer).CreateAsset(ctx, req.(*CreateAssetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DriverCommunication_Extinguish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ExtinguishRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverCommunicationServer).Extinguish(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DriverCommunication_Extinguish_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverCommunicationServer).Extinguish(ctx, req.(*ExtinguishRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DriverCommunication_AssignAsset_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AssignAssetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverCommunicationServer).AssignAsset(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DriverCommunication_AssignAsset_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverCommunicationServer).AssignAsset(ctx, req.(*AssignAssetRequest)) + } + return interceptor(ctx, in, info, handler) +} + // DriverCommunication_ServiceDesc is the grpc.ServiceDesc for DriverCommunication service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -235,6 +387,22 @@ var DriverCommunication_ServiceDesc = grpc.ServiceDesc{ MethodName: "WriteExternalState", Handler: _DriverCommunication_WriteExternalState_Handler, }, + { + MethodName: "PerformLock", + Handler: _DriverCommunication_PerformLock_Handler, + }, + { + MethodName: "CreateAsset", + Handler: _DriverCommunication_CreateAsset_Handler, + }, + { + MethodName: "Extinguish", + Handler: _DriverCommunication_Extinguish_Handler, + }, + { + MethodName: "AssignAsset", + Handler: _DriverCommunication_AssignAsset_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "driver/driver.proto", diff --git a/weaver/common/protos-go/fabric/view_data.pb.go b/weaver/common/protos-go/fabric/view_data.pb.go index 42367f47be..d2320f7369 100644 --- a/weaver/common/protos-go/fabric/view_data.pb.go +++ b/weaver/common/protos-go/fabric/view_data.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: fabric/view_data.proto package fabric diff --git a/weaver/common/protos-go/identity/agent.pb.go b/weaver/common/protos-go/identity/agent.pb.go index 97cc217a01..2423d1bdb2 100644 --- a/weaver/common/protos-go/identity/agent.pb.go +++ b/weaver/common/protos-go/identity/agent.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: identity/agent.proto package identity diff --git a/weaver/common/protos-go/identity/agent_grpc.pb.go b/weaver/common/protos-go/identity/agent_grpc.pb.go index 27005cdaa4..c0f7f20609 100644 --- a/weaver/common/protos-go/identity/agent_grpc.pb.go +++ b/weaver/common/protos-go/identity/agent_grpc.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.17.3 +// - protoc v3.12.4 // source: identity/agent.proto package identity diff --git a/weaver/common/protos-go/networks/networks.pb.go b/weaver/common/protos-go/networks/networks.pb.go index 5e1f7164b5..9b26730165 100644 --- a/weaver/common/protos-go/networks/networks.pb.go +++ b/weaver/common/protos-go/networks/networks.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: networks/networks.proto package networks @@ -392,6 +396,117 @@ func (x *NetworkEventUnsubscription) GetRequestId() string { return "" } +type NetworkAssetTransfer struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Policy []string `protobuf:"bytes,1,rep,name=policy,proto3" json:"policy,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + RequestingRelay string `protobuf:"bytes,3,opt,name=requesting_relay,json=requestingRelay,proto3" json:"requesting_relay,omitempty"` + RequestingNetwork string `protobuf:"bytes,4,opt,name=requesting_network,json=requestingNetwork,proto3" json:"requesting_network,omitempty"` + Certificate string `protobuf:"bytes,5,opt,name=certificate,proto3" json:"certificate,omitempty"` + RequestorSignature string `protobuf:"bytes,6,opt,name=requestor_signature,json=requestorSignature,proto3" json:"requestor_signature,omitempty"` + Nonce string `protobuf:"bytes,7,opt,name=nonce,proto3" json:"nonce,omitempty"` + RequestingOrg string `protobuf:"bytes,8,opt,name=requesting_org,json=requestingOrg,proto3" json:"requesting_org,omitempty"` + Confidential bool `protobuf:"varint,9,opt,name=confidential,proto3" json:"confidential,omitempty"` +} + +func (x *NetworkAssetTransfer) Reset() { + *x = NetworkAssetTransfer{} + if protoimpl.UnsafeEnabled { + mi := &file_networks_networks_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NetworkAssetTransfer) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetworkAssetTransfer) ProtoMessage() {} + +func (x *NetworkAssetTransfer) ProtoReflect() protoreflect.Message { + mi := &file_networks_networks_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetworkAssetTransfer.ProtoReflect.Descriptor instead. +func (*NetworkAssetTransfer) Descriptor() ([]byte, []int) { + return file_networks_networks_proto_rawDescGZIP(), []int{6} +} + +func (x *NetworkAssetTransfer) GetPolicy() []string { + if x != nil { + return x.Policy + } + return nil +} + +func (x *NetworkAssetTransfer) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *NetworkAssetTransfer) GetRequestingRelay() string { + if x != nil { + return x.RequestingRelay + } + return "" +} + +func (x *NetworkAssetTransfer) GetRequestingNetwork() string { + if x != nil { + return x.RequestingNetwork + } + return "" +} + +func (x *NetworkAssetTransfer) GetCertificate() string { + if x != nil { + return x.Certificate + } + return "" +} + +func (x *NetworkAssetTransfer) GetRequestorSignature() string { + if x != nil { + return x.RequestorSignature + } + return "" +} + +func (x *NetworkAssetTransfer) GetNonce() string { + if x != nil { + return x.Nonce + } + return "" +} + +func (x *NetworkAssetTransfer) GetRequestingOrg() string { + if x != nil { + return x.RequestingOrg + } + return "" +} + +func (x *NetworkAssetTransfer) GetConfidential() bool { + if x != nil { + return x.Confidential + } + return false +} + var File_networks_networks_proto protoreflect.FileDescriptor var file_networks_networks_proto_rawDesc = []byte{ @@ -459,53 +574,79 @@ var file_networks_networks_proto_rawDesc = []byte{ 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x32, 0xd3, 0x04, 0x0a, 0x07, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x42, 0x0a, 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x08, 0x47, 0x65, 0x74, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0xd6, 0x02, 0x0a, 0x14, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x12, + 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x20, + 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x12, 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x72, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x72, 0x67, 0x12, 0x22, + 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x32, 0xa7, 0x05, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x42, + 0x0a, 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, + 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, + 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, + 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, + 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x44, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x20, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x52, 0x0a, 0x14, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x27, 0x2e, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x66, 0x65, 0x72, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, + 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, + 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x68, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x44, - 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x20, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, - 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x2e, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x68, 0x0a, 0x19, 0x47, - 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x25, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x10, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x2e, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0e, 0x47, - 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x22, 0x2e, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x22, 0x00, 0x42, - 0x79, 0x0a, 0x35, 0x6f, 0x72, 0x67, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, - 0x65, 0x72, 0x2e, 0x63, 0x61, 0x63, 0x74, 0x69, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, - 0x2f, 0x63, 0x61, 0x63, 0x74, 0x69, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2f, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x76, - 0x32, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x25, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x22, 0x00, 0x12, 0x54, 0x0a, 0x10, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, + 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, + 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1a, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x22, 0x00, 0x42, 0x79, 0x0a, 0x35, + 0x6f, 0x72, 0x67, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2e, + 0x63, 0x61, 0x63, 0x74, 0x69, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2f, 0x63, 0x61, + 0x63, 0x74, 0x69, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -520,7 +661,7 @@ func file_networks_networks_proto_rawDescGZIP() []byte { return file_networks_networks_proto_rawDescData } -var file_networks_networks_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_networks_networks_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_networks_networks_proto_goTypes = []interface{}{ (*DbName)(nil), // 0: networks.networks.DbName (*RelayDatabase)(nil), // 1: networks.networks.RelayDatabase @@ -528,36 +669,39 @@ var file_networks_networks_proto_goTypes = []interface{}{ (*NetworkQuery)(nil), // 3: networks.networks.NetworkQuery (*NetworkEventSubscription)(nil), // 4: networks.networks.NetworkEventSubscription (*NetworkEventUnsubscription)(nil), // 5: networks.networks.NetworkEventUnsubscription - nil, // 6: networks.networks.RelayDatabase.PairsEntry - (*common.EventMatcher)(nil), // 7: common.events.EventMatcher - (*common.EventPublication)(nil), // 8: common.events.EventPublication - (*common.Ack)(nil), // 9: common.ack.Ack - (*common.RequestState)(nil), // 10: common.state.RequestState - (*common.EventSubscriptionState)(nil), // 11: common.events.EventSubscriptionState - (*common.EventStates)(nil), // 12: common.events.EventStates + (*NetworkAssetTransfer)(nil), // 6: networks.networks.NetworkAssetTransfer + nil, // 7: networks.networks.RelayDatabase.PairsEntry + (*common.EventMatcher)(nil), // 8: common.events.EventMatcher + (*common.EventPublication)(nil), // 9: common.events.EventPublication + (*common.Ack)(nil), // 10: common.ack.Ack + (*common.RequestState)(nil), // 11: common.state.RequestState + (*common.EventSubscriptionState)(nil), // 12: common.events.EventSubscriptionState + (*common.EventStates)(nil), // 13: common.events.EventStates } var file_networks_networks_proto_depIdxs = []int32{ - 6, // 0: networks.networks.RelayDatabase.pairs:type_name -> networks.networks.RelayDatabase.PairsEntry - 7, // 1: networks.networks.NetworkEventSubscription.event_matcher:type_name -> common.events.EventMatcher + 7, // 0: networks.networks.RelayDatabase.pairs:type_name -> networks.networks.RelayDatabase.PairsEntry + 8, // 1: networks.networks.NetworkEventSubscription.event_matcher:type_name -> common.events.EventMatcher 3, // 2: networks.networks.NetworkEventSubscription.query:type_name -> networks.networks.NetworkQuery - 8, // 3: networks.networks.NetworkEventSubscription.event_publication_spec:type_name -> common.events.EventPublication + 9, // 3: networks.networks.NetworkEventSubscription.event_publication_spec:type_name -> common.events.EventPublication 4, // 4: networks.networks.NetworkEventUnsubscription.request:type_name -> networks.networks.NetworkEventSubscription 3, // 5: networks.networks.Network.RequestState:input_type -> networks.networks.NetworkQuery 2, // 6: networks.networks.Network.GetState:input_type -> networks.networks.GetStateMessage 0, // 7: networks.networks.Network.RequestDatabase:input_type -> networks.networks.DbName - 4, // 8: networks.networks.Network.SubscribeEvent:input_type -> networks.networks.NetworkEventSubscription - 2, // 9: networks.networks.Network.GetEventSubscriptionState:input_type -> networks.networks.GetStateMessage - 5, // 10: networks.networks.Network.UnsubscribeEvent:input_type -> networks.networks.NetworkEventUnsubscription - 2, // 11: networks.networks.Network.GetEventStates:input_type -> networks.networks.GetStateMessage - 9, // 12: networks.networks.Network.RequestState:output_type -> common.ack.Ack - 10, // 13: networks.networks.Network.GetState:output_type -> common.state.RequestState - 1, // 14: networks.networks.Network.RequestDatabase:output_type -> networks.networks.RelayDatabase - 9, // 15: networks.networks.Network.SubscribeEvent:output_type -> common.ack.Ack - 11, // 16: networks.networks.Network.GetEventSubscriptionState:output_type -> common.events.EventSubscriptionState - 9, // 17: networks.networks.Network.UnsubscribeEvent:output_type -> common.ack.Ack - 12, // 18: networks.networks.Network.GetEventStates:output_type -> common.events.EventStates - 12, // [12:19] is the sub-list for method output_type - 5, // [5:12] is the sub-list for method input_type + 6, // 8: networks.networks.Network.RequestAssetTransfer:input_type -> networks.networks.NetworkAssetTransfer + 4, // 9: networks.networks.Network.SubscribeEvent:input_type -> networks.networks.NetworkEventSubscription + 2, // 10: networks.networks.Network.GetEventSubscriptionState:input_type -> networks.networks.GetStateMessage + 5, // 11: networks.networks.Network.UnsubscribeEvent:input_type -> networks.networks.NetworkEventUnsubscription + 2, // 12: networks.networks.Network.GetEventStates:input_type -> networks.networks.GetStateMessage + 10, // 13: networks.networks.Network.RequestState:output_type -> common.ack.Ack + 11, // 14: networks.networks.Network.GetState:output_type -> common.state.RequestState + 1, // 15: networks.networks.Network.RequestDatabase:output_type -> networks.networks.RelayDatabase + 10, // 16: networks.networks.Network.RequestAssetTransfer:output_type -> common.ack.Ack + 10, // 17: networks.networks.Network.SubscribeEvent:output_type -> common.ack.Ack + 12, // 18: networks.networks.Network.GetEventSubscriptionState:output_type -> common.events.EventSubscriptionState + 10, // 19: networks.networks.Network.UnsubscribeEvent:output_type -> common.ack.Ack + 13, // 20: networks.networks.Network.GetEventStates:output_type -> common.events.EventStates + 13, // [13:21] is the sub-list for method output_type + 5, // [5:13] is the sub-list for method input_type 5, // [5:5] is the sub-list for extension type_name 5, // [5:5] is the sub-list for extension extendee 0, // [0:5] is the sub-list for field type_name @@ -641,6 +785,18 @@ func file_networks_networks_proto_init() { return nil } } + file_networks_networks_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NetworkAssetTransfer); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -648,7 +804,7 @@ func file_networks_networks_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_networks_networks_proto_rawDesc, NumEnums: 0, - NumMessages: 7, + NumMessages: 8, NumExtensions: 0, NumServices: 1, }, diff --git a/weaver/common/protos-go/networks/networks_grpc.pb.go b/weaver/common/protos-go/networks/networks_grpc.pb.go index 089e1a295e..a150a6171b 100644 --- a/weaver/common/protos-go/networks/networks_grpc.pb.go +++ b/weaver/common/protos-go/networks/networks_grpc.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.17.3 +// - protoc v3.12.4 // source: networks/networks.proto package networks @@ -23,6 +27,7 @@ const ( Network_RequestState_FullMethodName = "/networks.networks.Network/RequestState" Network_GetState_FullMethodName = "/networks.networks.Network/GetState" Network_RequestDatabase_FullMethodName = "/networks.networks.Network/RequestDatabase" + Network_RequestAssetTransfer_FullMethodName = "/networks.networks.Network/RequestAssetTransfer" Network_SubscribeEvent_FullMethodName = "/networks.networks.Network/SubscribeEvent" Network_GetEventSubscriptionState_FullMethodName = "/networks.networks.Network/GetEventSubscriptionState" Network_UnsubscribeEvent_FullMethodName = "/networks.networks.Network/UnsubscribeEvent" @@ -40,6 +45,9 @@ type NetworkClient interface { GetState(ctx context.Context, in *GetStateMessage, opts ...grpc.CallOption) (*common.RequestState, error) // NOTE: This rpc is just for debugging. RequestDatabase(ctx context.Context, in *DbName, opts ...grpc.CallOption) (*RelayDatabase, error) + // SATP endpoints + // endpoint for a network to request asset transfer to a receiving gateway via local gateway + RequestAssetTransfer(ctx context.Context, in *NetworkAssetTransfer, opts ...grpc.CallOption) (*common.Ack, error) // Event endpoints // endpoint for a client to subscribe to event via local relay initiating subscription flow. SubscribeEvent(ctx context.Context, in *NetworkEventSubscription, opts ...grpc.CallOption) (*common.Ack, error) @@ -87,6 +95,15 @@ func (c *networkClient) RequestDatabase(ctx context.Context, in *DbName, opts .. return out, nil } +func (c *networkClient) RequestAssetTransfer(ctx context.Context, in *NetworkAssetTransfer, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, Network_RequestAssetTransfer_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *networkClient) SubscribeEvent(ctx context.Context, in *NetworkEventSubscription, opts ...grpc.CallOption) (*common.Ack, error) { out := new(common.Ack) err := c.cc.Invoke(ctx, Network_SubscribeEvent_FullMethodName, in, out, opts...) @@ -134,6 +151,9 @@ type NetworkServer interface { GetState(context.Context, *GetStateMessage) (*common.RequestState, error) // NOTE: This rpc is just for debugging. RequestDatabase(context.Context, *DbName) (*RelayDatabase, error) + // SATP endpoints + // endpoint for a network to request asset transfer to a receiving gateway via local gateway + RequestAssetTransfer(context.Context, *NetworkAssetTransfer) (*common.Ack, error) // Event endpoints // endpoint for a client to subscribe to event via local relay initiating subscription flow. SubscribeEvent(context.Context, *NetworkEventSubscription) (*common.Ack, error) @@ -160,6 +180,9 @@ func (UnimplementedNetworkServer) GetState(context.Context, *GetStateMessage) (* func (UnimplementedNetworkServer) RequestDatabase(context.Context, *DbName) (*RelayDatabase, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestDatabase not implemented") } +func (UnimplementedNetworkServer) RequestAssetTransfer(context.Context, *NetworkAssetTransfer) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method RequestAssetTransfer not implemented") +} func (UnimplementedNetworkServer) SubscribeEvent(context.Context, *NetworkEventSubscription) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method SubscribeEvent not implemented") } @@ -239,6 +262,24 @@ func _Network_RequestDatabase_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Network_RequestAssetTransfer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NetworkAssetTransfer) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NetworkServer).RequestAssetTransfer(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Network_RequestAssetTransfer_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NetworkServer).RequestAssetTransfer(ctx, req.(*NetworkAssetTransfer)) + } + return interceptor(ctx, in, info, handler) +} + func _Network_SubscribeEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(NetworkEventSubscription) if err := dec(in); err != nil { @@ -330,6 +371,10 @@ var Network_ServiceDesc = grpc.ServiceDesc{ MethodName: "RequestDatabase", Handler: _Network_RequestDatabase_Handler, }, + { + MethodName: "RequestAssetTransfer", + Handler: _Network_RequestAssetTransfer_Handler, + }, { MethodName: "SubscribeEvent", Handler: _Network_SubscribeEvent_Handler, diff --git a/weaver/common/protos-rs/pkg/src/generated/common.ack.rs b/weaver/common/protos-rs/pkg/src/generated/common.ack.rs index c4f738bddc..08185356b2 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.ack.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.ack.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// This message respresents "ACKs" sent between relay-relay, /// relay-driver and relay-network #[derive(serde::Serialize, serde::Deserialize)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.events.rs b/weaver/common/protos-rs/pkg/src/generated/common.events.rs index 5d2ffd24ff..745791664b 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.events.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.events.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.query.rs b/weaver/common/protos-rs/pkg/src/generated/common.query.rs index 65ce10d958..870b27fb3f 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.query.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.query.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// the payload to define the data that is being requested #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.state.rs b/weaver/common/protos-rs/pkg/src/generated/common.state.rs index 47e28979f4..dbeb44d563 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.state.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.state.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// Metadata for a View #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs index a9b21a94f1..1a89c27a54 100644 --- a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs +++ b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// Data for a View processing by dest-driver #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs index aefd5c53eb..0e556add31 100644 --- a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs +++ b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs b/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs index a3d738d3f8..21227fde93 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// Generated client implementations. pub mod data_transfer_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.events.rs b/weaver/common/protos-rs/pkg/src/generated/relay.events.rs index d8f258b622..50785f0d56 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.events.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.events.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// Generated client implementations. pub mod event_subscribe_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] diff --git a/weaver/core/relay/src/services/helpers.rs b/weaver/core/relay/src/services/helpers.rs index 2c8b5e6194..c3df19b069 100644 --- a/weaver/core/relay/src/services/helpers.rs +++ b/weaver/core/relay/src/services/helpers.rs @@ -2,7 +2,10 @@ // // SPDX-License-Identifier: Apache-2.0 +use colored::Colorize; use weaverpb::common::ack::{ack}; +use weaverpb::common::events::{event_subscription_state, EventSubscriptionState}; +use weaverpb::common::events::{EventPublication, EventState, EventStates, EventSubscription}; use weaverpb::common::query::Query; use weaverpb::common::state::{request_state, RequestState}; use weaverpb::driver::driver::driver_communication_client::DriverCommunicationClient; diff --git a/weaver/samples/fabric/satpsimpleasset/go.mod b/weaver/samples/fabric/satpsimpleasset/go.mod index a7d64f87cf..eedb9f8ddb 100644 --- a/weaver/samples/fabric/satpsimpleasset/go.mod +++ b/weaver/samples/fabric/satpsimpleasset/go.mod @@ -6,7 +6,7 @@ require ( github.com/golang/protobuf v1.5.3 github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 - github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils v0.0.0-20210920170720-5d5bf2a54081 + github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils v0.0.0-20230907062207-cd6eb2f89fb4 github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a github.com/hyperledger/fabric-contract-api-go v1.2.1 github.com/hyperledger/fabric-protos-go v0.3.0 diff --git a/weaver/samples/fabric/satpsimpleasset/go.sum b/weaver/samples/fabric/satpsimpleasset/go.sum index 23646b5a4f..da4c985ffd 100644 --- a/weaver/samples/fabric/satpsimpleasset/go.sum +++ b/weaver/samples/fabric/satpsimpleasset/go.sum @@ -147,11 +147,3 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha-prerelease h1:MpVTzM8FvQ+2Qij/0DH0cGy2NoC1S5gD5c40HuEQlsI= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha-prerelease/go.mod h1:3DmkYfZoc+TtcAgF3kX6CmQDNKKKCHgbaoQuYu/3ayc= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha-prerelease h1:kks9cM6vS3raV6Ag6FTddFdy11LvUAc6oYHVRUU95ts= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha-prerelease/go.mod h1:jzOMrtkM1AwBUgfedRs7FkcZpl1g/eRe1wnQO9GEoio= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 h1:r7RknfMWs/riL4saBB31iWfRaP03AJuo19K2ettHP3E= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1/go.mod h1:3DmkYfZoc+TtcAgF3kX6CmQDNKKKCHgbaoQuYu/3ayc= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 h1:ssYji+cWvfnPYRBQyx7J/aBVTaVdHbb2gOQOLfVZRCw= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1/go.mod h1:zei2BRZv+Ln+3o5yr7K900LRpEDCiado8px0hoGuuco= From 099c946a3a1a57ae65553b6f10202c8108abbda1 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Wed, 2 Aug 2023 10:04:33 +0100 Subject: [PATCH 41/59] Squashed commit: first implementation version of satp implemented the lock assertion method Added the lock-assertion-receipt and lock-assertion-broadcast methods Added the request to the driver to lock an asset corrected some variable names Added the endpoints corresponding to the steps 3.1 to 3.9 Implemented the step 2.1B so that the driver call the gateway to update the asset status Implemented the status check functionality required for 2.1B, 3.2B, 3.4B, and 3.6B First iteration of switching to real driver (fabric) Added the required functions to call back the gateway after the asset is locked. initial commit Initial commit for create-asset, extinguish, and assign-asset Added the resources required to assign an asset uncommented the perform lock part corrected compile error due to merging issue --- tools/go-gen-checksum.sh | 1 + weaver/common/protos-go/build-protos.sh | 2 +- .../protos-go/common/access_control.pb.go | 6 +- weaver/common/protos-go/common/ack.pb.go | 6 +- .../common/protos-go/common/asset_locks.pb.go | 6 +- .../protos-go/common/asset_transfer.pb.go | 6 +- weaver/common/protos-go/common/events.pb.go | 6 +- .../protos-go/common/interop_payload.pb.go | 6 +- .../common/protos-go/common/membership.pb.go | 6 +- weaver/common/protos-go/common/proofs.pb.go | 6 +- weaver/common/protos-go/common/query.pb.go | 6 +- weaver/common/protos-go/common/state.pb.go | 6 +- .../common/verification_policy.pb.go | 6 +- weaver/common/protos-go/corda/view_data.pb.go | 6 +- weaver/common/protos-go/driver/driver.pb.go | 386 ++++- .../common/protos-go/driver/driver_grpc.pb.go | 170 +- .../common/protos-go/fabric/view_data.pb.go | 6 +- weaver/common/protos-go/identity/agent.pb.go | 6 +- .../protos-go/identity/agent_grpc.pb.go | 6 +- .../common/protos-go/networks/networks.pb.go | 298 +++- .../protos-go/networks/networks_grpc.pb.go | 47 +- weaver/common/protos-js/build-protos.sh | 4 +- .../protos-rs/pkg/src/generated/common.ack.rs | 4 - .../pkg/src/generated/common.events.rs | 4 - .../pkg/src/generated/common.query.rs | 4 - .../pkg/src/generated/common.state.rs | 4 - .../pkg/src/generated/driver.driver.rs | 322 +++- .../pkg/src/generated/networks.networks.rs | 4 - .../pkg/src/generated/relay.datatransfer.rs | 4 - .../pkg/src/generated/relay.events.rs | 4 - .../protos-rs/pkg/src/generated/relay.satp.rs | 498 +++++- weaver/common/protos/driver/driver.proto | 32 + weaver/common/protos/relay/satp.proto | 54 + .../server/helpers/fabric-functions.ts | 714 +++++++++ .../fabric-driver/server/helpers/helpers.ts | 764 +++++++++ .../interop-setup/configure-network.ts | 230 +++ .../fabric-driver/server/helpers/logger.ts | 29 + .../core/drivers/fabric-driver/server/satp.ts | 389 +++++ .../drivers/fabric-driver/server/server.ts | 86 + weaver/core/relay/Cargo.lock | 66 +- weaver/core/relay/Cargo.toml | 1 + weaver/core/relay/config/Dummy_Relay.toml | 2 +- weaver/core/relay/driver/driver.rs | 184 ++- weaver/core/relay/src/services/helpers.rs | 235 ++- .../relay/src/services/network_service.rs | 16 +- weaver/core/relay/src/services/satp_helper.rs | 770 ++++++++- .../core/relay/src/services/satp_service.rs | 1402 ++++++++++++++--- .../samples/fabric/satpsimpleasset/.gitignore | 4 + .../samples/fabric/satpsimpleasset/Makefile | 27 + .../fabric/satpsimpleasset/assetmgmt.go | 360 +++++ .../fabric/satpsimpleasset/assetmgmt_test.go | 232 +++ .../fabric/satpsimpleasset/bondasset.go | 327 ++++ .../fabric/satpsimpleasset/bondasset_test.go | 242 +++ weaver/samples/fabric/satpsimpleasset/go.mod | 42 + weaver/samples/fabric/satpsimpleasset/go.sum | 149 ++ .../samples/fabric/satpsimpleasset/helper.go | 53 + weaver/samples/fabric/satpsimpleasset/main.go | 59 + .../fabric/satpsimpleasset/tokenasset.go | 316 ++++ .../fabric/satpsimpleasset/tokenasset_test.go | 326 ++++ .../fabric/interoperation-node-sdk/index.js | 1 + .../src/AssetManager.ts | 59 + .../src/SatpAssetManager.ts | 1111 +++++++++++++ .../interoperation-node-sdk/types/index.d.ts | 2 + .../fabric/dev/scripts/deployCC.sh | 4 + 64 files changed, 9608 insertions(+), 526 deletions(-) create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/helpers.ts create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts create mode 100644 weaver/core/drivers/fabric-driver/server/helpers/logger.ts create mode 100644 weaver/core/drivers/fabric-driver/server/satp.ts create mode 100644 weaver/samples/fabric/satpsimpleasset/.gitignore create mode 100644 weaver/samples/fabric/satpsimpleasset/Makefile create mode 100644 weaver/samples/fabric/satpsimpleasset/assetmgmt.go create mode 100644 weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go create mode 100644 weaver/samples/fabric/satpsimpleasset/bondasset.go create mode 100644 weaver/samples/fabric/satpsimpleasset/bondasset_test.go create mode 100644 weaver/samples/fabric/satpsimpleasset/go.mod create mode 100644 weaver/samples/fabric/satpsimpleasset/go.sum create mode 100644 weaver/samples/fabric/satpsimpleasset/helper.go create mode 100644 weaver/samples/fabric/satpsimpleasset/main.go create mode 100644 weaver/samples/fabric/satpsimpleasset/tokenasset.go create mode 100644 weaver/samples/fabric/satpsimpleasset/tokenasset_test.go create mode 100644 weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts diff --git a/tools/go-gen-checksum.sh b/tools/go-gen-checksum.sh index 87ef776051..513a5afd04 100755 --- a/tools/go-gen-checksum.sh +++ b/tools/go-gen-checksum.sh @@ -16,6 +16,7 @@ GOMODULE_PATHS=("weaver/core/network/fabric-interop-cc/libs/utils" "weaver/sdks/fabric/go-sdk" "weaver/samples/fabric/go-cli" "weaver/samples/fabric/simpleasset" +"weaver/samples/fabric/satpsimpleasset" "weaver/samples/fabric/simpleassetandinterop" "weaver/samples/fabric/simpleassettransfer" "weaver/samples/fabric/simplestatewithacl" diff --git a/weaver/common/protos-go/build-protos.sh b/weaver/common/protos-go/build-protos.sh index 0abbd7ac0c..19a6c4563a 100644 --- a/weaver/common/protos-go/build-protos.sh +++ b/weaver/common/protos-go/build-protos.sh @@ -12,6 +12,6 @@ protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go_out=$BUILDDIR protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go_out=$BUILDDIR --go_opt=paths=source_relative $PROTOSDIR/fabric/view_data.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go_out=$BUILDDIR --go_opt=paths=source_relative $PROTOSDIR/corda/view_data.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/networks/networks.proto -protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto PROTOSDIR/relay/satp.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/driver/driver.proto protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --go-grpc_out=paths=source_relative:$BUILDDIR --go_out=paths=source_relative:$BUILDDIR $PROTOSDIR/identity/agent.proto diff --git a/weaver/common/protos-go/common/access_control.pb.go b/weaver/common/protos-go/common/access_control.pb.go index 7e2383c003..266a1c203d 100644 --- a/weaver/common/protos-go/common/access_control.pb.go +++ b/weaver/common/protos-go/common/access_control.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/access_control.proto package common diff --git a/weaver/common/protos-go/common/ack.pb.go b/weaver/common/protos-go/common/ack.pb.go index 4d2fcb76b6..0b97f2fa93 100644 --- a/weaver/common/protos-go/common/ack.pb.go +++ b/weaver/common/protos-go/common/ack.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/ack.proto package common diff --git a/weaver/common/protos-go/common/asset_locks.pb.go b/weaver/common/protos-go/common/asset_locks.pb.go index eebb5939ab..d844467dc6 100644 --- a/weaver/common/protos-go/common/asset_locks.pb.go +++ b/weaver/common/protos-go/common/asset_locks.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/asset_locks.proto package common diff --git a/weaver/common/protos-go/common/asset_transfer.pb.go b/weaver/common/protos-go/common/asset_transfer.pb.go index de8b050302..1e930e39b0 100644 --- a/weaver/common/protos-go/common/asset_transfer.pb.go +++ b/weaver/common/protos-go/common/asset_transfer.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/asset_transfer.proto package common diff --git a/weaver/common/protos-go/common/events.pb.go b/weaver/common/protos-go/common/events.pb.go index 06eb16548e..da4ced1927 100644 --- a/weaver/common/protos-go/common/events.pb.go +++ b/weaver/common/protos-go/common/events.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/events.proto package common diff --git a/weaver/common/protos-go/common/interop_payload.pb.go b/weaver/common/protos-go/common/interop_payload.pb.go index 0f17f37359..0a1d3c5492 100644 --- a/weaver/common/protos-go/common/interop_payload.pb.go +++ b/weaver/common/protos-go/common/interop_payload.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/interop_payload.proto package common diff --git a/weaver/common/protos-go/common/membership.pb.go b/weaver/common/protos-go/common/membership.pb.go index d851d53dbf..124f30a1a2 100644 --- a/weaver/common/protos-go/common/membership.pb.go +++ b/weaver/common/protos-go/common/membership.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/membership.proto package common diff --git a/weaver/common/protos-go/common/proofs.pb.go b/weaver/common/protos-go/common/proofs.pb.go index 9c225d199c..5611cd3ee5 100644 --- a/weaver/common/protos-go/common/proofs.pb.go +++ b/weaver/common/protos-go/common/proofs.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/proofs.proto package common diff --git a/weaver/common/protos-go/common/query.pb.go b/weaver/common/protos-go/common/query.pb.go index f4b9f17bed..e66e708342 100644 --- a/weaver/common/protos-go/common/query.pb.go +++ b/weaver/common/protos-go/common/query.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/query.proto package common diff --git a/weaver/common/protos-go/common/state.pb.go b/weaver/common/protos-go/common/state.pb.go index fa68086ea5..30d8c72c85 100644 --- a/weaver/common/protos-go/common/state.pb.go +++ b/weaver/common/protos-go/common/state.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/state.proto package common diff --git a/weaver/common/protos-go/common/verification_policy.pb.go b/weaver/common/protos-go/common/verification_policy.pb.go index 26d80f9158..bbdac635f4 100644 --- a/weaver/common/protos-go/common/verification_policy.pb.go +++ b/weaver/common/protos-go/common/verification_policy.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: common/verification_policy.proto package common diff --git a/weaver/common/protos-go/corda/view_data.pb.go b/weaver/common/protos-go/corda/view_data.pb.go index 37f9bd8b6a..720eca12ac 100644 --- a/weaver/common/protos-go/corda/view_data.pb.go +++ b/weaver/common/protos-go/corda/view_data.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: corda/view_data.proto package corda diff --git a/weaver/common/protos-go/driver/driver.pb.go b/weaver/common/protos-go/driver/driver.pb.go index 764501f673..5ed253b931 100644 --- a/weaver/common/protos-go/driver/driver.pb.go +++ b/weaver/common/protos-go/driver/driver.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: driver/driver.proto package driver @@ -77,6 +81,194 @@ func (x *WriteExternalStateMessage) GetCtx() *common.ContractTransaction { return nil } +type PerformLockRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` +} + +func (x *PerformLockRequest) Reset() { + *x = PerformLockRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_driver_driver_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PerformLockRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PerformLockRequest) ProtoMessage() {} + +func (x *PerformLockRequest) ProtoReflect() protoreflect.Message { + mi := &file_driver_driver_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PerformLockRequest.ProtoReflect.Descriptor instead. +func (*PerformLockRequest) Descriptor() ([]byte, []int) { + return file_driver_driver_proto_rawDescGZIP(), []int{1} +} + +func (x *PerformLockRequest) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +type CreateAssetRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` +} + +func (x *CreateAssetRequest) Reset() { + *x = CreateAssetRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_driver_driver_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateAssetRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAssetRequest) ProtoMessage() {} + +func (x *CreateAssetRequest) ProtoReflect() protoreflect.Message { + mi := &file_driver_driver_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAssetRequest.ProtoReflect.Descriptor instead. +func (*CreateAssetRequest) Descriptor() ([]byte, []int) { + return file_driver_driver_proto_rawDescGZIP(), []int{2} +} + +func (x *CreateAssetRequest) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +type ExtinguishRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` +} + +func (x *ExtinguishRequest) Reset() { + *x = ExtinguishRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_driver_driver_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExtinguishRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExtinguishRequest) ProtoMessage() {} + +func (x *ExtinguishRequest) ProtoReflect() protoreflect.Message { + mi := &file_driver_driver_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExtinguishRequest.ProtoReflect.Descriptor instead. +func (*ExtinguishRequest) Descriptor() ([]byte, []int) { + return file_driver_driver_proto_rawDescGZIP(), []int{3} +} + +func (x *ExtinguishRequest) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + +type AssignAssetRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SessionId string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` +} + +func (x *AssignAssetRequest) Reset() { + *x = AssignAssetRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_driver_driver_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AssignAssetRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AssignAssetRequest) ProtoMessage() {} + +func (x *AssignAssetRequest) ProtoReflect() protoreflect.Message { + mi := &file_driver_driver_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AssignAssetRequest.ProtoReflect.Descriptor instead. +func (*AssignAssetRequest) Descriptor() ([]byte, []int) { + return file_driver_driver_proto_rawDescGZIP(), []int{4} +} + +func (x *AssignAssetRequest) GetSessionId() string { + if x != nil { + return x.SessionId + } + return "" +} + var File_driver_driver_proto protoreflect.FileDescriptor var file_driver_driver_proto_rawDesc = []byte{ @@ -96,36 +288,66 @@ var file_driver_driver_proto_rawDesc = []byte{ 0x34, 0x0a, 0x03, 0x63, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x03, 0x63, 0x74, 0x78, 0x32, 0xcd, 0x02, 0x0a, 0x13, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, - 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, - 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, - 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0e, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, + 0x52, 0x03, 0x63, 0x74, 0x78, 0x22, 0x33, 0x0a, 0x12, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, + 0x4c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x33, 0x0a, 0x12, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, + 0x32, 0x0a, 0x11, 0x45, 0x78, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x22, 0x33, 0x0a, 0x12, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x32, 0xdf, 0x04, 0x0a, 0x13, 0x44, 0x72, 0x69, + 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x3c, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, + 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x45, + 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x23, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x20, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x13, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x12, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x2e, 0x64, 0x72, + 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x57, 0x72, 0x69, 0x74, + 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, + 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x66, + 0x6f, 0x72, 0x6d, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x21, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, + 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x4c, + 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x43, 0x0a, + 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x21, 0x2e, 0x64, + 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, - 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x23, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x69, 0x67, - 0x6e, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x13, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x22, 0x00, 0x12, 0x51, 0x0a, 0x12, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x28, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, - 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x78, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, - 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x73, 0x0a, 0x31, 0x6f, 0x72, 0x67, 0x2e, 0x68, 0x79, 0x70, - 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2e, 0x63, 0x61, 0x63, 0x74, 0x69, 0x2e, 0x77, - 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x64, 0x72, 0x69, - 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, - 0x65, 0x72, 0x2f, 0x63, 0x61, 0x63, 0x74, 0x69, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2f, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, - 0x2f, 0x76, 0x32, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0a, 0x45, 0x78, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, + 0x12, 0x20, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, + 0x2e, 0x45, 0x78, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, + 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0b, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x12, 0x21, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, + 0x69, 0x76, 0x65, 0x72, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x41, 0x73, 0x73, 0x65, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x73, 0x0a, 0x31, 0x6f, 0x72, + 0x67, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2e, 0x63, 0x61, + 0x63, 0x74, 0x69, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x73, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x5a, + 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, + 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2f, 0x63, 0x61, 0x63, 0x74, 0x69, 0x2f, 0x77, 0x65, + 0x61, 0x76, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -140,31 +362,43 @@ func file_driver_driver_proto_rawDescGZIP() []byte { return file_driver_driver_proto_rawDescData } -var file_driver_driver_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_driver_driver_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_driver_driver_proto_goTypes = []interface{}{ (*WriteExternalStateMessage)(nil), // 0: driver.driver.WriteExternalStateMessage - (*common.ViewPayload)(nil), // 1: common.state.ViewPayload - (*common.ContractTransaction)(nil), // 2: common.events.ContractTransaction - (*common.Query)(nil), // 3: common.query.Query - (*common.EventSubscription)(nil), // 4: common.events.EventSubscription - (*common.Ack)(nil), // 5: common.ack.Ack + (*PerformLockRequest)(nil), // 1: driver.driver.PerformLockRequest + (*CreateAssetRequest)(nil), // 2: driver.driver.CreateAssetRequest + (*ExtinguishRequest)(nil), // 3: driver.driver.ExtinguishRequest + (*AssignAssetRequest)(nil), // 4: driver.driver.AssignAssetRequest + (*common.ViewPayload)(nil), // 5: common.state.ViewPayload + (*common.ContractTransaction)(nil), // 6: common.events.ContractTransaction + (*common.Query)(nil), // 7: common.query.Query + (*common.EventSubscription)(nil), // 8: common.events.EventSubscription + (*common.Ack)(nil), // 9: common.ack.Ack } var file_driver_driver_proto_depIdxs = []int32{ - 1, // 0: driver.driver.WriteExternalStateMessage.view_payload:type_name -> common.state.ViewPayload - 2, // 1: driver.driver.WriteExternalStateMessage.ctx:type_name -> common.events.ContractTransaction - 3, // 2: driver.driver.DriverCommunication.RequestDriverState:input_type -> common.query.Query - 4, // 3: driver.driver.DriverCommunication.SubscribeEvent:input_type -> common.events.EventSubscription - 4, // 4: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:input_type -> common.events.EventSubscription - 0, // 5: driver.driver.DriverCommunication.WriteExternalState:input_type -> driver.driver.WriteExternalStateMessage - 5, // 6: driver.driver.DriverCommunication.RequestDriverState:output_type -> common.ack.Ack - 5, // 7: driver.driver.DriverCommunication.SubscribeEvent:output_type -> common.ack.Ack - 3, // 8: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:output_type -> common.query.Query - 5, // 9: driver.driver.DriverCommunication.WriteExternalState:output_type -> common.ack.Ack - 6, // [6:10] is the sub-list for method output_type - 2, // [2:6] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 5, // 0: driver.driver.WriteExternalStateMessage.view_payload:type_name -> common.state.ViewPayload + 6, // 1: driver.driver.WriteExternalStateMessage.ctx:type_name -> common.events.ContractTransaction + 7, // 2: driver.driver.DriverCommunication.RequestDriverState:input_type -> common.query.Query + 8, // 3: driver.driver.DriverCommunication.SubscribeEvent:input_type -> common.events.EventSubscription + 8, // 4: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:input_type -> common.events.EventSubscription + 0, // 5: driver.driver.DriverCommunication.WriteExternalState:input_type -> driver.driver.WriteExternalStateMessage + 1, // 6: driver.driver.DriverCommunication.PerformLock:input_type -> driver.driver.PerformLockRequest + 2, // 7: driver.driver.DriverCommunication.CreateAsset:input_type -> driver.driver.CreateAssetRequest + 3, // 8: driver.driver.DriverCommunication.Extinguish:input_type -> driver.driver.ExtinguishRequest + 4, // 9: driver.driver.DriverCommunication.AssignAsset:input_type -> driver.driver.AssignAssetRequest + 9, // 10: driver.driver.DriverCommunication.RequestDriverState:output_type -> common.ack.Ack + 9, // 11: driver.driver.DriverCommunication.SubscribeEvent:output_type -> common.ack.Ack + 7, // 12: driver.driver.DriverCommunication.RequestSignedEventSubscriptionQuery:output_type -> common.query.Query + 9, // 13: driver.driver.DriverCommunication.WriteExternalState:output_type -> common.ack.Ack + 9, // 14: driver.driver.DriverCommunication.PerformLock:output_type -> common.ack.Ack + 9, // 15: driver.driver.DriverCommunication.CreateAsset:output_type -> common.ack.Ack + 9, // 16: driver.driver.DriverCommunication.Extinguish:output_type -> common.ack.Ack + 9, // 17: driver.driver.DriverCommunication.AssignAsset:output_type -> common.ack.Ack + 10, // [10:18] is the sub-list for method output_type + 2, // [2:10] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_driver_driver_proto_init() } @@ -185,6 +419,54 @@ func file_driver_driver_proto_init() { return nil } } + file_driver_driver_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PerformLockRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_driver_driver_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateAssetRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_driver_driver_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExtinguishRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_driver_driver_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AssignAssetRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -192,7 +474,7 @@ func file_driver_driver_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_driver_driver_proto_rawDesc, NumEnums: 0, - NumMessages: 1, + NumMessages: 5, NumExtensions: 0, NumServices: 1, }, diff --git a/weaver/common/protos-go/driver/driver_grpc.pb.go b/weaver/common/protos-go/driver/driver_grpc.pb.go index 08d8741e82..ce978ce6f6 100644 --- a/weaver/common/protos-go/driver/driver_grpc.pb.go +++ b/weaver/common/protos-go/driver/driver_grpc.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.17.3 +// - protoc v3.12.4 // source: driver/driver.proto package driver @@ -24,6 +28,10 @@ const ( DriverCommunication_SubscribeEvent_FullMethodName = "/driver.driver.DriverCommunication/SubscribeEvent" DriverCommunication_RequestSignedEventSubscriptionQuery_FullMethodName = "/driver.driver.DriverCommunication/RequestSignedEventSubscriptionQuery" DriverCommunication_WriteExternalState_FullMethodName = "/driver.driver.DriverCommunication/WriteExternalState" + DriverCommunication_PerformLock_FullMethodName = "/driver.driver.DriverCommunication/PerformLock" + DriverCommunication_CreateAsset_FullMethodName = "/driver.driver.DriverCommunication/CreateAsset" + DriverCommunication_Extinguish_FullMethodName = "/driver.driver.DriverCommunication/Extinguish" + DriverCommunication_AssignAsset_FullMethodName = "/driver.driver.DriverCommunication/AssignAsset" ) // DriverCommunicationClient is the client API for DriverCommunication service. @@ -44,6 +52,18 @@ type DriverCommunicationClient interface { // Events Publication // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger WriteExternalState(ctx context.Context, in *WriteExternalStateMessage, opts ...grpc.CallOption) (*common.Ack, error) + // As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver + // to lock a specific asset + PerformLock(ctx context.Context, in *PerformLockRequest, opts ...grpc.CallOption) (*common.Ack, error) + // As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + // to create a specific asset + CreateAsset(ctx context.Context, in *CreateAssetRequest, opts ...grpc.CallOption) (*common.Ack, error) + // As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + // to extinguish a specific asset + Extinguish(ctx context.Context, in *ExtinguishRequest, opts ...grpc.CallOption) (*common.Ack, error) + // As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + // to assign a specific asset + AssignAsset(ctx context.Context, in *AssignAssetRequest, opts ...grpc.CallOption) (*common.Ack, error) } type driverCommunicationClient struct { @@ -90,6 +110,42 @@ func (c *driverCommunicationClient) WriteExternalState(ctx context.Context, in * return out, nil } +func (c *driverCommunicationClient) PerformLock(ctx context.Context, in *PerformLockRequest, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, DriverCommunication_PerformLock_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *driverCommunicationClient) CreateAsset(ctx context.Context, in *CreateAssetRequest, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, DriverCommunication_CreateAsset_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *driverCommunicationClient) Extinguish(ctx context.Context, in *ExtinguishRequest, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, DriverCommunication_Extinguish_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *driverCommunicationClient) AssignAsset(ctx context.Context, in *AssignAssetRequest, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, DriverCommunication_AssignAsset_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DriverCommunicationServer is the server API for DriverCommunication service. // All implementations must embed UnimplementedDriverCommunicationServer // for forward compatibility @@ -108,6 +164,18 @@ type DriverCommunicationServer interface { // Events Publication // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger WriteExternalState(context.Context, *WriteExternalStateMessage) (*common.Ack, error) + // As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver + // to lock a specific asset + PerformLock(context.Context, *PerformLockRequest) (*common.Ack, error) + // As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + // to create a specific asset + CreateAsset(context.Context, *CreateAssetRequest) (*common.Ack, error) + // As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + // to extinguish a specific asset + Extinguish(context.Context, *ExtinguishRequest) (*common.Ack, error) + // As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + // to assign a specific asset + AssignAsset(context.Context, *AssignAssetRequest) (*common.Ack, error) mustEmbedUnimplementedDriverCommunicationServer() } @@ -127,6 +195,18 @@ func (UnimplementedDriverCommunicationServer) RequestSignedEventSubscriptionQuer func (UnimplementedDriverCommunicationServer) WriteExternalState(context.Context, *WriteExternalStateMessage) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method WriteExternalState not implemented") } +func (UnimplementedDriverCommunicationServer) PerformLock(context.Context, *PerformLockRequest) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method PerformLock not implemented") +} +func (UnimplementedDriverCommunicationServer) CreateAsset(context.Context, *CreateAssetRequest) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateAsset not implemented") +} +func (UnimplementedDriverCommunicationServer) Extinguish(context.Context, *ExtinguishRequest) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method Extinguish not implemented") +} +func (UnimplementedDriverCommunicationServer) AssignAsset(context.Context, *AssignAssetRequest) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method AssignAsset not implemented") +} func (UnimplementedDriverCommunicationServer) mustEmbedUnimplementedDriverCommunicationServer() {} // UnsafeDriverCommunicationServer may be embedded to opt out of forward compatibility for this service. @@ -212,6 +292,78 @@ func _DriverCommunication_WriteExternalState_Handler(srv interface{}, ctx contex return interceptor(ctx, in, info, handler) } +func _DriverCommunication_PerformLock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PerformLockRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverCommunicationServer).PerformLock(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DriverCommunication_PerformLock_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverCommunicationServer).PerformLock(ctx, req.(*PerformLockRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DriverCommunication_CreateAsset_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateAssetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverCommunicationServer).CreateAsset(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DriverCommunication_CreateAsset_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverCommunicationServer).CreateAsset(ctx, req.(*CreateAssetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DriverCommunication_Extinguish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ExtinguishRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverCommunicationServer).Extinguish(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DriverCommunication_Extinguish_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverCommunicationServer).Extinguish(ctx, req.(*ExtinguishRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _DriverCommunication_AssignAsset_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AssignAssetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DriverCommunicationServer).AssignAsset(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DriverCommunication_AssignAsset_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DriverCommunicationServer).AssignAsset(ctx, req.(*AssignAssetRequest)) + } + return interceptor(ctx, in, info, handler) +} + // DriverCommunication_ServiceDesc is the grpc.ServiceDesc for DriverCommunication service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -235,6 +387,22 @@ var DriverCommunication_ServiceDesc = grpc.ServiceDesc{ MethodName: "WriteExternalState", Handler: _DriverCommunication_WriteExternalState_Handler, }, + { + MethodName: "PerformLock", + Handler: _DriverCommunication_PerformLock_Handler, + }, + { + MethodName: "CreateAsset", + Handler: _DriverCommunication_CreateAsset_Handler, + }, + { + MethodName: "Extinguish", + Handler: _DriverCommunication_Extinguish_Handler, + }, + { + MethodName: "AssignAsset", + Handler: _DriverCommunication_AssignAsset_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "driver/driver.proto", diff --git a/weaver/common/protos-go/fabric/view_data.pb.go b/weaver/common/protos-go/fabric/view_data.pb.go index 42367f47be..d2320f7369 100644 --- a/weaver/common/protos-go/fabric/view_data.pb.go +++ b/weaver/common/protos-go/fabric/view_data.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: fabric/view_data.proto package fabric diff --git a/weaver/common/protos-go/identity/agent.pb.go b/weaver/common/protos-go/identity/agent.pb.go index 97cc217a01..2423d1bdb2 100644 --- a/weaver/common/protos-go/identity/agent.pb.go +++ b/weaver/common/protos-go/identity/agent.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: identity/agent.proto package identity diff --git a/weaver/common/protos-go/identity/agent_grpc.pb.go b/weaver/common/protos-go/identity/agent_grpc.pb.go index 27005cdaa4..c0f7f20609 100644 --- a/weaver/common/protos-go/identity/agent_grpc.pb.go +++ b/weaver/common/protos-go/identity/agent_grpc.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.17.3 +// - protoc v3.12.4 // source: identity/agent.proto package identity diff --git a/weaver/common/protos-go/networks/networks.pb.go b/weaver/common/protos-go/networks/networks.pb.go index 5e1f7164b5..9b26730165 100644 --- a/weaver/common/protos-go/networks/networks.pb.go +++ b/weaver/common/protos-go/networks/networks.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.17.3 +// protoc v3.12.4 // source: networks/networks.proto package networks @@ -392,6 +396,117 @@ func (x *NetworkEventUnsubscription) GetRequestId() string { return "" } +type NetworkAssetTransfer struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Policy []string `protobuf:"bytes,1,rep,name=policy,proto3" json:"policy,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + RequestingRelay string `protobuf:"bytes,3,opt,name=requesting_relay,json=requestingRelay,proto3" json:"requesting_relay,omitempty"` + RequestingNetwork string `protobuf:"bytes,4,opt,name=requesting_network,json=requestingNetwork,proto3" json:"requesting_network,omitempty"` + Certificate string `protobuf:"bytes,5,opt,name=certificate,proto3" json:"certificate,omitempty"` + RequestorSignature string `protobuf:"bytes,6,opt,name=requestor_signature,json=requestorSignature,proto3" json:"requestor_signature,omitempty"` + Nonce string `protobuf:"bytes,7,opt,name=nonce,proto3" json:"nonce,omitempty"` + RequestingOrg string `protobuf:"bytes,8,opt,name=requesting_org,json=requestingOrg,proto3" json:"requesting_org,omitempty"` + Confidential bool `protobuf:"varint,9,opt,name=confidential,proto3" json:"confidential,omitempty"` +} + +func (x *NetworkAssetTransfer) Reset() { + *x = NetworkAssetTransfer{} + if protoimpl.UnsafeEnabled { + mi := &file_networks_networks_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NetworkAssetTransfer) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetworkAssetTransfer) ProtoMessage() {} + +func (x *NetworkAssetTransfer) ProtoReflect() protoreflect.Message { + mi := &file_networks_networks_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use NetworkAssetTransfer.ProtoReflect.Descriptor instead. +func (*NetworkAssetTransfer) Descriptor() ([]byte, []int) { + return file_networks_networks_proto_rawDescGZIP(), []int{6} +} + +func (x *NetworkAssetTransfer) GetPolicy() []string { + if x != nil { + return x.Policy + } + return nil +} + +func (x *NetworkAssetTransfer) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *NetworkAssetTransfer) GetRequestingRelay() string { + if x != nil { + return x.RequestingRelay + } + return "" +} + +func (x *NetworkAssetTransfer) GetRequestingNetwork() string { + if x != nil { + return x.RequestingNetwork + } + return "" +} + +func (x *NetworkAssetTransfer) GetCertificate() string { + if x != nil { + return x.Certificate + } + return "" +} + +func (x *NetworkAssetTransfer) GetRequestorSignature() string { + if x != nil { + return x.RequestorSignature + } + return "" +} + +func (x *NetworkAssetTransfer) GetNonce() string { + if x != nil { + return x.Nonce + } + return "" +} + +func (x *NetworkAssetTransfer) GetRequestingOrg() string { + if x != nil { + return x.RequestingOrg + } + return "" +} + +func (x *NetworkAssetTransfer) GetConfidential() bool { + if x != nil { + return x.Confidential + } + return false +} + var File_networks_networks_proto protoreflect.FileDescriptor var file_networks_networks_proto_rawDesc = []byte{ @@ -459,53 +574,79 @@ var file_networks_networks_proto_rawDesc = []byte{ 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x32, 0xd3, 0x04, 0x0a, 0x07, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x42, 0x0a, 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x08, 0x47, 0x65, 0x74, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0x22, 0xd6, 0x02, 0x0a, 0x14, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x12, + 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x20, + 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x12, 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6f, 0x72, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x4f, 0x72, 0x67, 0x12, 0x22, + 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x32, 0xa7, 0x05, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x12, 0x42, + 0x0a, 0x0c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1f, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, + 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, + 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, + 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, + 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x44, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x20, + 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x52, 0x0a, 0x14, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x27, 0x2e, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x41, 0x73, 0x73, 0x65, 0x74, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x66, 0x65, 0x72, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, 0x63, 0x6b, + 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, + 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x68, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x19, 0x2e, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x44, - 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x20, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, - 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0e, 0x53, 0x75, 0x62, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2b, 0x2e, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x68, 0x0a, 0x19, 0x47, - 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, 0x65, 0x74, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x25, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x10, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x2e, 0x6e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x61, 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0e, 0x47, - 0x65, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x22, 0x2e, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x1a, 0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x22, 0x00, 0x42, - 0x79, 0x0a, 0x35, 0x6f, 0x72, 0x67, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, - 0x65, 0x72, 0x2e, 0x63, 0x61, 0x63, 0x74, 0x69, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, - 0x2f, 0x63, 0x61, 0x63, 0x74, 0x69, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2f, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x76, - 0x32, 0x2f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x25, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x22, 0x00, 0x12, 0x54, 0x0a, 0x10, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x61, + 0x63, 0x6b, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x47, + 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1a, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x22, 0x00, 0x42, 0x79, 0x0a, 0x35, + 0x6f, 0x72, 0x67, 0x2e, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2e, + 0x63, 0x61, 0x63, 0x74, 0x69, 0x2e, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x2e, 0x6e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2f, 0x63, 0x61, + 0x63, 0x74, 0x69, 0x2f, 0x77, 0x65, 0x61, 0x76, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x76, 0x32, 0x2f, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -520,7 +661,7 @@ func file_networks_networks_proto_rawDescGZIP() []byte { return file_networks_networks_proto_rawDescData } -var file_networks_networks_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_networks_networks_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_networks_networks_proto_goTypes = []interface{}{ (*DbName)(nil), // 0: networks.networks.DbName (*RelayDatabase)(nil), // 1: networks.networks.RelayDatabase @@ -528,36 +669,39 @@ var file_networks_networks_proto_goTypes = []interface{}{ (*NetworkQuery)(nil), // 3: networks.networks.NetworkQuery (*NetworkEventSubscription)(nil), // 4: networks.networks.NetworkEventSubscription (*NetworkEventUnsubscription)(nil), // 5: networks.networks.NetworkEventUnsubscription - nil, // 6: networks.networks.RelayDatabase.PairsEntry - (*common.EventMatcher)(nil), // 7: common.events.EventMatcher - (*common.EventPublication)(nil), // 8: common.events.EventPublication - (*common.Ack)(nil), // 9: common.ack.Ack - (*common.RequestState)(nil), // 10: common.state.RequestState - (*common.EventSubscriptionState)(nil), // 11: common.events.EventSubscriptionState - (*common.EventStates)(nil), // 12: common.events.EventStates + (*NetworkAssetTransfer)(nil), // 6: networks.networks.NetworkAssetTransfer + nil, // 7: networks.networks.RelayDatabase.PairsEntry + (*common.EventMatcher)(nil), // 8: common.events.EventMatcher + (*common.EventPublication)(nil), // 9: common.events.EventPublication + (*common.Ack)(nil), // 10: common.ack.Ack + (*common.RequestState)(nil), // 11: common.state.RequestState + (*common.EventSubscriptionState)(nil), // 12: common.events.EventSubscriptionState + (*common.EventStates)(nil), // 13: common.events.EventStates } var file_networks_networks_proto_depIdxs = []int32{ - 6, // 0: networks.networks.RelayDatabase.pairs:type_name -> networks.networks.RelayDatabase.PairsEntry - 7, // 1: networks.networks.NetworkEventSubscription.event_matcher:type_name -> common.events.EventMatcher + 7, // 0: networks.networks.RelayDatabase.pairs:type_name -> networks.networks.RelayDatabase.PairsEntry + 8, // 1: networks.networks.NetworkEventSubscription.event_matcher:type_name -> common.events.EventMatcher 3, // 2: networks.networks.NetworkEventSubscription.query:type_name -> networks.networks.NetworkQuery - 8, // 3: networks.networks.NetworkEventSubscription.event_publication_spec:type_name -> common.events.EventPublication + 9, // 3: networks.networks.NetworkEventSubscription.event_publication_spec:type_name -> common.events.EventPublication 4, // 4: networks.networks.NetworkEventUnsubscription.request:type_name -> networks.networks.NetworkEventSubscription 3, // 5: networks.networks.Network.RequestState:input_type -> networks.networks.NetworkQuery 2, // 6: networks.networks.Network.GetState:input_type -> networks.networks.GetStateMessage 0, // 7: networks.networks.Network.RequestDatabase:input_type -> networks.networks.DbName - 4, // 8: networks.networks.Network.SubscribeEvent:input_type -> networks.networks.NetworkEventSubscription - 2, // 9: networks.networks.Network.GetEventSubscriptionState:input_type -> networks.networks.GetStateMessage - 5, // 10: networks.networks.Network.UnsubscribeEvent:input_type -> networks.networks.NetworkEventUnsubscription - 2, // 11: networks.networks.Network.GetEventStates:input_type -> networks.networks.GetStateMessage - 9, // 12: networks.networks.Network.RequestState:output_type -> common.ack.Ack - 10, // 13: networks.networks.Network.GetState:output_type -> common.state.RequestState - 1, // 14: networks.networks.Network.RequestDatabase:output_type -> networks.networks.RelayDatabase - 9, // 15: networks.networks.Network.SubscribeEvent:output_type -> common.ack.Ack - 11, // 16: networks.networks.Network.GetEventSubscriptionState:output_type -> common.events.EventSubscriptionState - 9, // 17: networks.networks.Network.UnsubscribeEvent:output_type -> common.ack.Ack - 12, // 18: networks.networks.Network.GetEventStates:output_type -> common.events.EventStates - 12, // [12:19] is the sub-list for method output_type - 5, // [5:12] is the sub-list for method input_type + 6, // 8: networks.networks.Network.RequestAssetTransfer:input_type -> networks.networks.NetworkAssetTransfer + 4, // 9: networks.networks.Network.SubscribeEvent:input_type -> networks.networks.NetworkEventSubscription + 2, // 10: networks.networks.Network.GetEventSubscriptionState:input_type -> networks.networks.GetStateMessage + 5, // 11: networks.networks.Network.UnsubscribeEvent:input_type -> networks.networks.NetworkEventUnsubscription + 2, // 12: networks.networks.Network.GetEventStates:input_type -> networks.networks.GetStateMessage + 10, // 13: networks.networks.Network.RequestState:output_type -> common.ack.Ack + 11, // 14: networks.networks.Network.GetState:output_type -> common.state.RequestState + 1, // 15: networks.networks.Network.RequestDatabase:output_type -> networks.networks.RelayDatabase + 10, // 16: networks.networks.Network.RequestAssetTransfer:output_type -> common.ack.Ack + 10, // 17: networks.networks.Network.SubscribeEvent:output_type -> common.ack.Ack + 12, // 18: networks.networks.Network.GetEventSubscriptionState:output_type -> common.events.EventSubscriptionState + 10, // 19: networks.networks.Network.UnsubscribeEvent:output_type -> common.ack.Ack + 13, // 20: networks.networks.Network.GetEventStates:output_type -> common.events.EventStates + 13, // [13:21] is the sub-list for method output_type + 5, // [5:13] is the sub-list for method input_type 5, // [5:5] is the sub-list for extension type_name 5, // [5:5] is the sub-list for extension extendee 0, // [0:5] is the sub-list for field type_name @@ -641,6 +785,18 @@ func file_networks_networks_proto_init() { return nil } } + file_networks_networks_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*NetworkAssetTransfer); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -648,7 +804,7 @@ func file_networks_networks_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_networks_networks_proto_rawDesc, NumEnums: 0, - NumMessages: 7, + NumMessages: 8, NumExtensions: 0, NumServices: 1, }, diff --git a/weaver/common/protos-go/networks/networks_grpc.pb.go b/weaver/common/protos-go/networks/networks_grpc.pb.go index 089e1a295e..a150a6171b 100644 --- a/weaver/common/protos-go/networks/networks_grpc.pb.go +++ b/weaver/common/protos-go/networks/networks_grpc.pb.go @@ -1,7 +1,11 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.17.3 +// - protoc v3.12.4 // source: networks/networks.proto package networks @@ -23,6 +27,7 @@ const ( Network_RequestState_FullMethodName = "/networks.networks.Network/RequestState" Network_GetState_FullMethodName = "/networks.networks.Network/GetState" Network_RequestDatabase_FullMethodName = "/networks.networks.Network/RequestDatabase" + Network_RequestAssetTransfer_FullMethodName = "/networks.networks.Network/RequestAssetTransfer" Network_SubscribeEvent_FullMethodName = "/networks.networks.Network/SubscribeEvent" Network_GetEventSubscriptionState_FullMethodName = "/networks.networks.Network/GetEventSubscriptionState" Network_UnsubscribeEvent_FullMethodName = "/networks.networks.Network/UnsubscribeEvent" @@ -40,6 +45,9 @@ type NetworkClient interface { GetState(ctx context.Context, in *GetStateMessage, opts ...grpc.CallOption) (*common.RequestState, error) // NOTE: This rpc is just for debugging. RequestDatabase(ctx context.Context, in *DbName, opts ...grpc.CallOption) (*RelayDatabase, error) + // SATP endpoints + // endpoint for a network to request asset transfer to a receiving gateway via local gateway + RequestAssetTransfer(ctx context.Context, in *NetworkAssetTransfer, opts ...grpc.CallOption) (*common.Ack, error) // Event endpoints // endpoint for a client to subscribe to event via local relay initiating subscription flow. SubscribeEvent(ctx context.Context, in *NetworkEventSubscription, opts ...grpc.CallOption) (*common.Ack, error) @@ -87,6 +95,15 @@ func (c *networkClient) RequestDatabase(ctx context.Context, in *DbName, opts .. return out, nil } +func (c *networkClient) RequestAssetTransfer(ctx context.Context, in *NetworkAssetTransfer, opts ...grpc.CallOption) (*common.Ack, error) { + out := new(common.Ack) + err := c.cc.Invoke(ctx, Network_RequestAssetTransfer_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *networkClient) SubscribeEvent(ctx context.Context, in *NetworkEventSubscription, opts ...grpc.CallOption) (*common.Ack, error) { out := new(common.Ack) err := c.cc.Invoke(ctx, Network_SubscribeEvent_FullMethodName, in, out, opts...) @@ -134,6 +151,9 @@ type NetworkServer interface { GetState(context.Context, *GetStateMessage) (*common.RequestState, error) // NOTE: This rpc is just for debugging. RequestDatabase(context.Context, *DbName) (*RelayDatabase, error) + // SATP endpoints + // endpoint for a network to request asset transfer to a receiving gateway via local gateway + RequestAssetTransfer(context.Context, *NetworkAssetTransfer) (*common.Ack, error) // Event endpoints // endpoint for a client to subscribe to event via local relay initiating subscription flow. SubscribeEvent(context.Context, *NetworkEventSubscription) (*common.Ack, error) @@ -160,6 +180,9 @@ func (UnimplementedNetworkServer) GetState(context.Context, *GetStateMessage) (* func (UnimplementedNetworkServer) RequestDatabase(context.Context, *DbName) (*RelayDatabase, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestDatabase not implemented") } +func (UnimplementedNetworkServer) RequestAssetTransfer(context.Context, *NetworkAssetTransfer) (*common.Ack, error) { + return nil, status.Errorf(codes.Unimplemented, "method RequestAssetTransfer not implemented") +} func (UnimplementedNetworkServer) SubscribeEvent(context.Context, *NetworkEventSubscription) (*common.Ack, error) { return nil, status.Errorf(codes.Unimplemented, "method SubscribeEvent not implemented") } @@ -239,6 +262,24 @@ func _Network_RequestDatabase_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Network_RequestAssetTransfer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NetworkAssetTransfer) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NetworkServer).RequestAssetTransfer(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Network_RequestAssetTransfer_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NetworkServer).RequestAssetTransfer(ctx, req.(*NetworkAssetTransfer)) + } + return interceptor(ctx, in, info, handler) +} + func _Network_SubscribeEvent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(NetworkEventSubscription) if err := dec(in); err != nil { @@ -330,6 +371,10 @@ var Network_ServiceDesc = grpc.ServiceDesc{ MethodName: "RequestDatabase", Handler: _Network_RequestDatabase_Handler, }, + { + MethodName: "RequestAssetTransfer", + Handler: _Network_RequestAssetTransfer_Handler, + }, { MethodName: "SubscribeEvent", Handler: _Network_SubscribeEvent_Handler, diff --git a/weaver/common/protos-js/build-protos.sh b/weaver/common/protos-js/build-protos.sh index 556e000112..d869c3bab9 100755 --- a/weaver/common/protos-js/build-protos.sh +++ b/weaver/common/protos-js/build-protos.sh @@ -17,7 +17,7 @@ grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR - grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/fabric/view_data.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/identity/agent.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/networks/networks.proto -grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --grpc_out=grpc_js:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto $PROTOSDIR/relay/satp.proto grpc_tools_node_protoc --proto_path=$PROTOSDIR --proto_path=$FABRIC_PROTOSDIR --js_out=import_style=commonjs,binary:$BUILDDIR --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto # Typescript Build @@ -27,5 +27,5 @@ protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDD protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/fabric/view_data.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/identity/agent.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/networks/networks.proto -protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto +protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $PROTOSDIR/relay/datatransfer.proto $PROTOSDIR/relay/events.proto $PROTOSDIR/relay/satp.proto protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=$BUILDDIR -I $PROTOSDIR -I $FABRIC_PROTOSDIR $FABRIC_PROTOSDIR/msp/identities.proto $FABRIC_PROTOSDIR/peer/proposal_response.proto $FABRIC_PROTOSDIR/peer/proposal.proto $FABRIC_PROTOSDIR/peer/chaincode.proto $FABRIC_PROTOSDIR/common/policies.proto $FABRIC_PROTOSDIR/msp/msp_principal.proto diff --git a/weaver/common/protos-rs/pkg/src/generated/common.ack.rs b/weaver/common/protos-rs/pkg/src/generated/common.ack.rs index c4f738bddc..08185356b2 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.ack.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.ack.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// This message respresents "ACKs" sent between relay-relay, /// relay-driver and relay-network #[derive(serde::Serialize, serde::Deserialize)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.events.rs b/weaver/common/protos-rs/pkg/src/generated/common.events.rs index 5d2ffd24ff..745791664b 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.events.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.events.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.query.rs b/weaver/common/protos-rs/pkg/src/generated/common.query.rs index 65ce10d958..870b27fb3f 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.query.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.query.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// the payload to define the data that is being requested #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.state.rs b/weaver/common/protos-rs/pkg/src/generated/common.state.rs index 47e28979f4..dbeb44d563 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.state.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.state.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// Metadata for a View #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs index b846c9e7d5..1a89c27a54 100644 --- a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs +++ b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// Data for a View processing by dest-driver #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] @@ -12,6 +8,34 @@ pub struct WriteExternalStateMessage { #[prost(message, optional, tag = "2")] pub ctx: ::core::option::Option, } +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PerformLockRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateAssetRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ExtinguishRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AssignAssetRequest { + #[prost(string, tag = "1")] + pub session_id: ::prost::alloc::string::String, +} /// Generated client implementations. pub mod driver_communication_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] @@ -183,6 +207,102 @@ pub mod driver_communication_client { ); self.inner.unary(request.into_request(), path, codec).await } + /// As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver + /// to lock a specific asset + pub async fn perform_lock( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/PerformLock", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + /// to create a specific asset + pub async fn create_asset( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/CreateAsset", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + /// to extinguish a specific asset + pub async fn extinguish( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/Extinguish", + ); + self.inner.unary(request.into_request(), path, codec).await + } + /// As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + /// to assign a specific asset + pub async fn assign_asset( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/driver.driver.DriverCommunication/AssignAsset", + ); + self.inner.unary(request.into_request(), path, codec).await + } } } /// Generated server implementations. @@ -234,6 +354,42 @@ pub mod driver_communication_server { tonic::Response, tonic::Status, >; + /// As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver + /// to lock a specific asset + async fn perform_lock( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + /// to create a specific asset + async fn create_asset( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + /// to extinguish a specific asset + async fn extinguish( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + /// As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + /// to assign a specific asset + async fn assign_asset( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct DriverCommunicationServer { @@ -469,6 +625,164 @@ pub mod driver_communication_server { }; Box::pin(fut) } + "/driver.driver.DriverCommunication/PerformLock" => { + #[allow(non_camel_case_types)] + struct PerformLockSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for PerformLockSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).perform_lock(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = PerformLockSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/driver.driver.DriverCommunication/CreateAsset" => { + #[allow(non_camel_case_types)] + struct CreateAssetSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for CreateAssetSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).create_asset(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CreateAssetSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/driver.driver.DriverCommunication/Extinguish" => { + #[allow(non_camel_case_types)] + struct ExtinguishSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for ExtinguishSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { (*inner).extinguish(request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = ExtinguishSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/driver.driver.DriverCommunication/AssignAsset" => { + #[allow(non_camel_case_types)] + struct AssignAssetSvc(pub Arc); + impl< + T: DriverCommunication, + > tonic::server::UnaryService + for AssignAssetSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).assign_asset(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = AssignAssetSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( diff --git a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs index aefd5c53eb..0e556add31 100644 --- a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs +++ b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs b/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs index a3d738d3f8..21227fde93 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// Generated client implementations. pub mod data_transfer_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.events.rs b/weaver/common/protos-rs/pkg/src/generated/relay.events.rs index d8f258b622..50785f0d56 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.events.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.events.rs @@ -1,7 +1,3 @@ -// Copyright IBM Corp. All Rights Reserved. -// -// SPDX-License-Identifier: Apache-2.0 - /// Generated client implementations. pub mod event_subscribe_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index 0031a5dacd..b7147bd954 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -107,6 +107,29 @@ pub struct AckCommenceRequest { #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct SendAssetStatusRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub client_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub server_identity_pubkey: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub hash_prev_message: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub server_transfer_number: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub server_signature: ::prost::alloc::string::String, + #[prost(string, tag = "9")] + pub status: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct LockAssertionRequest { #[prost(string, tag = "1")] pub message_type: ::prost::alloc::string::String, @@ -152,6 +175,61 @@ pub struct LockAssertionReceiptRequest { #[prost(string, tag = "8")] pub server_signature: ::prost::alloc::string::String, } +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommitPrepareRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommitReadyRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CommitFinalAssertionRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AckFinalReceiptRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransferCompletedRequest { + #[prost(string, tag = "1")] + pub message_type: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub session_id: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub transfer_context_id: ::prost::alloc::string::String, +} /// Generated client implementations. pub mod satp_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] @@ -221,7 +299,7 @@ pub mod satp_client { self.inner = self.inner.accept_compressed(encoding); self } - /// The sender gateway sends a TransferProposalClaims request to to initiate an asset transfer. + /// The sender gateway sends a TransferProposalClaims request to initiate an asset transfer. /// Depending on the proposal, multiple rounds of communication between the two gateways may happen. pub async fn transfer_proposal_claims( &mut self, @@ -317,9 +395,31 @@ pub mod satp_client { ); self.inner.unary(request.into_request(), path, codec).await } + pub async fn send_asset_status( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/SendAssetStatus", + ); + self.inner.unary(request.into_request(), path, codec).await + } /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway /// declaring that the asset in question has been locked or escrowed by the sender gateway in - /// the origin network (e.g. to prevent double spending + /// the origin network (e.g. to prevent double spending) pub async fn lock_assertion( &mut self, request: impl tonic::IntoRequest, @@ -366,6 +466,116 @@ pub mod satp_client { ); self.inner.unary(request.into_request(), path, codec).await } + pub async fn commit_prepare( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/CommitPrepare", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn commit_ready( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/CommitReady", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn commit_final_assertion( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/CommitFinalAssertion", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn ack_final_receipt( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/AckFinalReceipt", + ); + self.inner.unary(request.into_request(), path, codec).await + } + pub async fn transfer_completed( + &mut self, + request: impl tonic::IntoRequest, + ) -> Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/relay.satp.SATP/TransferCompleted", + ); + self.inner.unary(request.into_request(), path, codec).await + } } } /// Generated server implementations. @@ -375,7 +585,7 @@ pub mod satp_server { /// Generated trait containing gRPC methods that should be implemented for use with SatpServer. #[async_trait] pub trait Satp: Send + Sync + 'static { - /// The sender gateway sends a TransferProposalClaims request to to initiate an asset transfer. + /// The sender gateway sends a TransferProposalClaims request to initiate an asset transfer. /// Depending on the proposal, multiple rounds of communication between the two gateways may happen. async fn transfer_proposal_claims( &self, @@ -411,9 +621,16 @@ pub mod satp_server { tonic::Response, tonic::Status, >; + async fn send_asset_status( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; /// The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway /// declaring that the asset in question has been locked or escrowed by the sender gateway in - /// the origin network (e.g. to prevent double spending + /// the origin network (e.g. to prevent double spending) async fn lock_assertion( &self, request: tonic::Request, @@ -430,6 +647,41 @@ pub mod satp_server { tonic::Response, tonic::Status, >; + async fn commit_prepare( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn commit_ready( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn commit_final_assertion( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn ack_final_receipt( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; + async fn transfer_completed( + &self, + request: tonic::Request, + ) -> Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct SatpServer { @@ -650,6 +902,46 @@ pub mod satp_server { }; Box::pin(fut) } + "/relay.satp.SATP/SendAssetStatus" => { + #[allow(non_camel_case_types)] + struct SendAssetStatusSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for SendAssetStatusSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).send_asset_status(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = SendAssetStatusSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/relay.satp.SATP/LockAssertion" => { #[allow(non_camel_case_types)] struct LockAssertionSvc(pub Arc); @@ -730,6 +1022,204 @@ pub mod satp_server { }; Box::pin(fut) } + "/relay.satp.SATP/CommitPrepare" => { + #[allow(non_camel_case_types)] + struct CommitPrepareSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for CommitPrepareSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).commit_prepare(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommitPrepareSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/CommitReady" => { + #[allow(non_camel_case_types)] + struct CommitReadySvc(pub Arc); + impl tonic::server::UnaryService + for CommitReadySvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).commit_ready(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommitReadySvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/CommitFinalAssertion" => { + #[allow(non_camel_case_types)] + struct CommitFinalAssertionSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for CommitFinalAssertionSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).commit_final_assertion(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = CommitFinalAssertionSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/AckFinalReceipt" => { + #[allow(non_camel_case_types)] + struct AckFinalReceiptSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for AckFinalReceiptSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).ack_final_receipt(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = AckFinalReceiptSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/relay.satp.SATP/TransferCompleted" => { + #[allow(non_camel_case_types)] + struct TransferCompletedSvc(pub Arc); + impl< + T: Satp, + > tonic::server::UnaryService + for TransferCompletedSvc { + type Response = super::super::super::common::ack::Ack; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = self.0.clone(); + let fut = async move { + (*inner).transfer_completed(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = TransferCompletedSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { Ok( diff --git a/weaver/common/protos/driver/driver.proto b/weaver/common/protos/driver/driver.proto index fd12529aff..b0681f8e4f 100644 --- a/weaver/common/protos/driver/driver.proto +++ b/weaver/common/protos/driver/driver.proto @@ -20,6 +20,22 @@ message WriteExternalStateMessage { common.events.ContractTransaction ctx = 2; } +message PerformLockRequest { + string session_id = 1; +} + +message CreateAssetRequest { + string session_id = 1; +} + +message ExtinguishRequest { + string session_id = 1; +} + +message AssignAssetRequest { + string session_id = 1; +} + service DriverCommunication { // Data Sharing // the remote relay sends a RequestDriverState request to its driver with a @@ -38,4 +54,20 @@ service DriverCommunication { // Events Publication // the dest-relay calls the dest-driver on this end point to write the remote network state to the local ledger rpc WriteExternalState(WriteExternalStateMessage) returns (common.ack.Ack) {} + + // As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver + // to lock a specific asset + rpc PerformLock(PerformLockRequest) returns (common.ack.Ack) {} + + // As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + // to create a specific asset + rpc CreateAsset(CreateAssetRequest) returns (common.ack.Ack) {} + + // As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + // to extinguish a specific asset + rpc Extinguish(ExtinguishRequest) returns (common.ack.Ack) {} + + // As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + // to assign a specific asset + rpc AssignAsset(AssignAssetRequest) returns (common.ack.Ack) {} } \ No newline at end of file diff --git a/weaver/common/protos/relay/satp.proto b/weaver/common/protos/relay/satp.proto index 66d2bf7073..3d20759879 100644 --- a/weaver/common/protos/relay/satp.proto +++ b/weaver/common/protos/relay/satp.proto @@ -30,6 +30,8 @@ service SATP { // Stage 2 endpoints + rpc SendAssetStatus(SendAssetStatusRequest) returns (common.ack.Ack) {}; + // The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway // declaring that the asset in question has been locked or escrowed by the sender gateway in // the origin network (e.g. to prevent double spending) @@ -38,6 +40,16 @@ service SATP { // The receiver gateway sends a LockAssertionReceipt request to the sender gateway to indicate acceptance // of the claim(s) delivered by the sender gateway in the previous message rpc LockAssertionReceipt(LockAssertionReceiptRequest) returns (common.ack.Ack) {}; + + rpc CommitPrepare(CommitPrepareRequest) returns (common.ack.Ack) {}; + + rpc CommitReady(CommitReadyRequest) returns (common.ack.Ack) {}; + + rpc CommitFinalAssertion(CommitFinalAssertionRequest) returns (common.ack.Ack) {}; + + rpc AckFinalReceipt(AckFinalReceiptRequest) returns (common.ack.Ack) {}; + + rpc TransferCompleted(TransferCompletedRequest) returns (common.ack.Ack) {}; } message TransferProposalClaimsRequest { @@ -95,6 +107,18 @@ message AckCommenceRequest { string server_signature = 8; } +message SendAssetStatusRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_prev_message = 6; + string server_transfer_number = 7; + string server_signature = 8; + string status = 9; +} + message LockAssertionRequest { string message_type = 1; string session_id = 2; @@ -118,4 +142,34 @@ message LockAssertionReceiptRequest { string hash_prev_message = 6; string server_transfer_number = 7; string server_signature = 8; +} + +message CommitPrepareRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message CommitReadyRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message CommitFinalAssertionRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message AckFinalReceiptRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} + +message TransferCompletedRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; } \ No newline at end of file diff --git a/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts b/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts new file mode 100644 index 0000000000..08b7597980 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts @@ -0,0 +1,714 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Gateway, Wallets, Contract, X509Identity } from 'fabric-network' +import { getNetworkConfig, saveUserCertToFile, handlePromise } from './helpers' +import FabricCAServices from 'fabric-ca-client' +import { Certificate } from '@fidm/x509' +import { Utils, ICryptoKey } from 'fabric-common' +import * as membership_pb from "@hyperledger/cacti-weaver-protos-js/common/membership_pb" +import * as iin_agent_pb from "@hyperledger/cacti-weaver-protos-js/identity/agent_pb" +import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric' +import * as path from 'path' +import * as dotenv from 'dotenv' +dotenv.config({ path: path.resolve(__dirname, '../../.env') }) +import * as fs from 'fs' + +export type InvocationSpec = { + contractName: string + channel: string + args: string[] + ccFunc: string +} + +const getUserCertBase64 = async ( + networkName: string, + username: string +) => { + const wallet = await getWalletForNetwork(networkName) + const userId = await wallet.get(username) + if (!userId) { + throw new Error(`User ${username} not present in wallet of ${networkName}.`) + } + return Buffer.from((userId as X509Identity).credentials.certificate).toString('base64') +} + +const walletSetup = async ( + networkName: string, + ccp: any, + mspId: string, + userName: string, + userPwd: string = '', + isNetworkAdmin: boolean = false, + isIINAgent: boolean = false, + register: boolean = false, + logger: any = console +) => { + // Create a new CA client for interacting with the CA. + const org = ccp.client['organization'] + const caName = ccp.organizations[org]['certificateAuthorities'][0] + const caURL = ccp.certificateAuthorities[caName].url + const ca = new FabricCAServices(caURL) + const ident = ca.newIdentityService() + + const wallet = await getWalletForNetwork(networkName) + + // build a user object for authenticating with the CA + // Check to see if we've already enrolled the admin user. + let adminIdentity = await wallet.get('admin') + + if (adminIdentity) { + logger.debug( + 'An identity for the admin user "admin" already exists in the wallet.' + ) + } else { + // Enroll the admin user, and import the new identity into the wallet. + const enrollment = await ca.enroll({ + enrollmentID: 'admin', + enrollmentSecret: 'adminpw' + }) + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes() + }, + mspId: mspId, + type: 'X.509' + } + await wallet.put('admin', x509Identity) + adminIdentity = await wallet.get('admin') + } + const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type) + const adminUser = await provider.getUserContext(adminIdentity, 'admin') + const identity = await wallet.get(userName) + logger.debug(`user ${userName}`) + if (!identity) { + // Register the user, enroll the user, and import the new identity into the wallet. + if (!register) { + logger.error(`Identity ${userName} does not exist. Please add user in the network.\n`) + return + } + var secret, enrollment + var enrollmentDone = false + var attributes = [] + if (isNetworkAdmin) { + attributes.push({ "name": "network-admin", "value": "true", "ecert": true }) + } + if (isIINAgent) { + attributes.push({ "name": "iin-agent", "value": "true", "ecert": true }) + } + try { + if (!userPwd) { + secret = await ca.register( + { + affiliation: 'org1.department1', + enrollmentID: userName, + maxEnrollments: -1, + role: 'client', + attrs: attributes + }, + adminUser + ) + } + else { + secret = await ca.register( + { + affiliation: 'org1.department1', + enrollmentID: userName, + enrollmentSecret: userPwd, + maxEnrollments: -1, + role: 'client', + attrs: attributes + }, + adminUser + ) + } + logger.info(`Wallet Setup: Sucessful ${secret}`) + } catch(error) { + const registeredUser = `Identity '${userName}' is already ` + if (!userPwd || !(error.message.includes("Identity ") && error.message.includes(userName) && error.message.includes(" is already registered"))) { + throw new Error(`user ${userName} registration with Fabric CA failed with error: ${error}`) + } else { + try { + enrollment = await ca.enroll({ + enrollmentID: userName, + enrollmentSecret: userPwd + }) + enrollmentDone = true + } catch (error) { + throw new Error(`user ${userName} registration/enrollment with Fabric CA failed with error: ${error}`) + } + } + } + + if (!enrollmentDone) { + enrollment = await ca.enroll({ + enrollmentID: userName, + enrollmentSecret: secret + }) + } + + const x509Identity = { + credentials: { + certificate: enrollment.certificate, + privateKey: enrollment.key.toBytes() + }, + mspId: mspId, + type: 'X.509' + } + await wallet.put(userName, x509Identity) + } + else { + logger.debug(`Identity ${userName} already exists.\n`) + } + + return wallet +} + +const enrollAndRecordWalletIdentity = async ( + userName: string, + userPwd: string, + networkName: string, + isNetworkAdmin: boolean = false, + isIINAgent: boolean = false, + logger: any = console +) => { + const net = getNetworkConfig(networkName) + const ccpPath = path.resolve(__dirname, net.connProfilePath) + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) + logger.info(net) + + const wallet = await walletSetup(networkName, ccp, net.mspId, userName, userPwd, isNetworkAdmin, isIINAgent, true) + saveUserCertToFile(userName, networkName) + + return wallet +} + +const getCurrentNetworkCredentialPath = (networkName: string): string => { + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, networkName) + : path.join(__dirname, '../data', 'credentials', networkName) + return credentialsPath +} + +const getCredentialPath = (): string => { + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER) + : path.join(__dirname, '../data', 'credentials') + return credentialsPath +} + +const generateAccessControl = async ( + channel: string, + contractName: string, + connProfilePath: string, + networkName: string, + templatePath: string, + username: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console +): Promise => { + const { wallet } = await fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + logger, + mspId + }) + const templateJSON = JSON.parse( + Buffer.from(fs.readFileSync(templatePath)).toString() + ) + const [keyCert, keyCertError] = await handlePromise( + getKeyAndCertForRemoteRequestbyUserName(wallet, username) + ) + if (keyCertError) { + logger.error( + 'Error fetching key and certificate from network', + keyCertError + ) + } + const updatedRules = templateJSON.rules.map(rule => { + if (rule.principalType == 'ca') { + rule.principal = mspId + } else if (rule.principalType == 'certificate') { + rule.principal = keyCert.cert + } else { + logger.error( + 'Error Invalid Principal Type in template file' + ) + } + return rule + }) + const accessControlJSON = { + ...templateJSON, + securityDomain: networkName, + rules: updatedRules + } + logger.debug(`AccessControlJSON ${JSON.stringify(accessControlJSON)}`) + const credentialsPath = getCurrentNetworkCredentialPath(networkName) + fs.writeFileSync( + path.join(credentialsPath, `access-control.json`), + JSON.stringify(accessControlJSON) + ) +} + +const generateVerificationPolicy = async ( + channel, + contractName, + connProfilePath, + networkName: string, + templatePath: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console +): Promise => { + const templateJSON = JSON.parse( + Buffer.from(fs.readFileSync(templatePath)).toString() + ) + const { gateway } = await fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + mspId, + logger + }) + + const network = await gateway.getNetwork(channel) + const mspConfig = await getMspConfig(network, logger) + const criteria = Object.keys(formatMSP(mspConfig, networkName).members) + const newIdentifiers = templateJSON.identifiers.map(identifier => { + identifier.policy.criteria = criteria + return identifier + }) + const verificationPolicy = { + ...templateJSON, + identifiers: newIdentifiers, + securityDomain: networkName + } + logger.debug(`VerificationPolicyJSON ${JSON.stringify(verificationPolicy)}`) + const credentialsPath = getCurrentNetworkCredentialPath(networkName) + logger.debug('Credential Path', credentialsPath) + fs.writeFileSync( + path.join(credentialsPath, `verification-policy.json`), + JSON.stringify(verificationPolicy) + ) +} + +const generateMembership = async ( + channel: string, + contractName: string, + connProfilePath: string, + networkName: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console, + iinAgent: boolean = false +): Promise => { + const { gateway } = await fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + mspId, + logger + }) + + const network = await gateway.getNetwork(channel) + const mspConfig = await getMspConfig(network, logger) + const membershipJSON = formatMSP(mspConfig, networkName) + const membershipJSONStr = JSON.stringify(membershipJSON) + logger.debug(`membershipJSON: ${membershipJSONStr}`) + + const credentialsPath = getCurrentNetworkCredentialPath(networkName) + logger.debug(`Credentials Path: ${credentialsPath}`) + if (!fs.existsSync(credentialsPath)) { + logger.debug(`Creating directory`) + fs.mkdirSync(credentialsPath, { recursive: true }) + } + + fs.writeFileSync( + path.join(credentialsPath, `membership.json`), + membershipJSONStr + ) + + if (iinAgent) { + // Generate protobufs and attestations for all other networks that have IIN Agents + const credentialFolderPath = getCredentialPath() + const otherNetworkNames = fs + .readdirSync(credentialFolderPath, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .filter(item => item.name.startsWith('network')) // HACK until we add IIN Agents for Corda networks + .map(item => item.name) + // Reorder the array so that the local network is the first element + // We need to record local membership before recording other networks' memberships + otherNetworkNames.splice(otherNetworkNames.indexOf(networkName), 1) + + if (otherNetworkNames.length > 0) { + // Convert membership object to protobuf + let membershipProto = new membership_pb.Membership() + membershipProto.setSecuritydomain(membershipJSON.securityDomain) + Object.keys(membershipJSON.members).forEach( (memberName, index) => { + const certInfo = membershipJSON.members[memberName] + let memberProto = new membership_pb.Member() + memberProto.setType(certInfo.type) + memberProto.setValue(certInfo.value) + membershipProto.getMembersMap().set(memberName, memberProto) + }) + + // For every other network, generate a counter attested membership set + const serializedMembership = membershipProto.serializeBinary() + const serializedMembershipBase64 = Buffer.from(serializedMembership).toString('base64') + const nonce = 'j849j94j40f440fkfjkld0e043' // Some random string + const membershipBase64WithNonce = serializedMembershipBase64 + nonce + // Get wallet key and cert for this network's IIN Agent + const localWallet = await getWalletForNetwork(networkName) + const localKeyCert = await getKeyAndCertForRemoteRequestbyUserName(localWallet, 'iinagent') + // Sign using wallet identity + let securityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() + securityDomainMember.setSecurityDomain(membershipJSON.securityDomain) + securityDomainMember.setMemberId(Object.keys(membershipJSON.members)[0]) + let localAttestation = new iin_agent_pb.Attestation() + localAttestation.setUnitIdentity(securityDomainMember) + localAttestation.setCertificate(localKeyCert.cert) + const localSig = InteroperableHelper.signMessage(membershipBase64WithNonce, localKeyCert.key.toBytes()) + localAttestation.setSignature(localSig) + localAttestation.setNonce(nonce) + let attestedMembershipSet = new iin_agent_pb.CounterAttestedMembership.AttestedMembershipSet() + attestedMembershipSet.setMembership(serializedMembershipBase64) + attestedMembershipSet.setAttestationsList( [ localAttestation ] ) + const serializedAttestedMembershipSet = attestedMembershipSet.serializeBinary() + const serializedttestedMembershipSetBase64 = Buffer.from(serializedAttestedMembershipSet).toString('base64') + const serializedttestedMembershipSetBase64WithNonce = serializedttestedMembershipSetBase64 + nonce + for (const otherNetworkName of otherNetworkNames) { + // Get wallet key and cert for other network's IIN Agent + const otherWallet = await getWalletForNetwork(otherNetworkName) + const otherKeyCert = await getKeyAndCertForRemoteRequestbyUserName(otherWallet, 'iinagent') + // Sign using wallet identity + let otherSecurityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() + otherSecurityDomainMember.setSecurityDomain(otherNetworkName) + otherSecurityDomainMember.setMemberId(getNetworkConfig(otherNetworkName).mspId) + let otherAttestation = new iin_agent_pb.Attestation() + otherAttestation.setUnitIdentity(otherSecurityDomainMember) + otherAttestation.setCertificate(otherKeyCert.cert) + const otherSig = InteroperableHelper.signMessage(serializedttestedMembershipSetBase64WithNonce, otherKeyCert.key.toBytes()) + otherAttestation.setSignature(otherSig) + otherAttestation.setNonce(nonce) + + // Generate chaincode argument and save it in a file + let counterAttestedMembership = new iin_agent_pb.CounterAttestedMembership() + counterAttestedMembership.setAttestedMembershipSet(serializedttestedMembershipSetBase64) + counterAttestedMembership.setAttestationsList( [ otherAttestation ] ) + + fs.writeFileSync( + path.join(credentialsPath, `attested-membership-${otherNetworkName}.proto.serialized`), + Buffer.from(counterAttestedMembership.serializeBinary()).toString('base64') + ) + } + } + } + return membershipJSON +} + +const formatMSP = (mspConfig: MspConfig, networkId: string) => { + const memberObject = { members: {}, securityDomain: networkId } + Object.entries(mspConfig).forEach(([name, value], _) => { + // const cert = Certificate.fromPEM(Buffer.from(value.root_certs[0], 'base64')) + memberObject.members[name] = { + type: 'ca', + value: Buffer.from(value.root_certs[0], 'base64').toString('utf8') + } + }) + return memberObject +} + +type MspConfig = { + [key: string]: { admins: any; root_certs: any; name: string } +} + +const getMspConfig = async ( + network, + logger: any = console +): Promise => { + const mspConfigs = network.channel.getMspids() + const orgMspConfig = {} + logger.debug(mspConfigs) + logger.debug(network.channel.getMsp(mspConfigs[0])) + + mspConfigs.forEach(mspId => { + if (mspId !== 'OrdererMSP') { + logger.info('Getting MSP Info for org with MSP ID: ' + mspId + '.') + const mspConfig = network.getChannel().getMsp(mspId) + delete mspConfig.id + if (Array.isArray(mspConfig.admins)) { + for (let i = 0; i < mspConfig.admins.length; i++) { + mspConfig.admins[i] = Buffer.from(mspConfig.admins[i]).toString( + 'base64' + ) + } + } else if (mspConfig.admins.length === 0) { + mspConfig.admins = [] + } else { + mspConfig.admins = [Buffer.from(mspConfig.admins).toString('base64')] + } + if (Array.isArray(mspConfig.rootCerts)) { + for (let i = 0; i < mspConfig.rootCerts.length; i++) { + mspConfig.rootCerts[i] = Buffer.from(mspConfig.rootCerts[i]).toString( + 'base64' + ) + } + } else if (mspConfig.rootCerts.length === 0) { + mspConfig.rootCerts = [] + } else { + mspConfig.rootCerts = [ + Buffer.from(mspConfig.rootCerts).toString('base64') + ] + } + mspConfig.root_certs = mspConfig.rootCerts + delete mspConfig.rootCerts + if (Array.isArray(mspConfig.intermediateCerts)) { + for (let i = 0; i < mspConfig.intermediateCerts.length; i++) { + mspConfig.intermediateCerts[i] = Buffer.from( + mspConfig.intermediateCerts[i] + ).toString('base64') + } + } else if (mspConfig.intermediateCerts.length === 0) { + mspConfig.intermediateCerts = [] + } else { + mspConfig.intermediateCerts = [ + Buffer.from(mspConfig.intermediateCerts).toString('base64') + ] + } + mspConfig.intermediate_certs = mspConfig.intermediateCerts + delete mspConfig.intermediateCerts + if (Array.isArray(mspConfig.tlsRootCerts)) { + for (let i = 0; i < mspConfig.tlsRootCerts.length; i++) { + mspConfig.tlsRootCerts[i] = Buffer.from( + mspConfig.tlsRootCerts[i] + ).toString('base64') + } + } else if (mspConfig.tlsRootCerts.length === 0) { + mspConfig.tlsRootCerts = [] + } else { + mspConfig.tlsRootCerts = [ + Buffer.from(mspConfig.tlsRootCerts).toString('base64') + ] + } + mspConfig.tls_root_certs = mspConfig.tlsRootCerts + delete mspConfig.tlsRootCerts + if (Array.isArray(mspConfig.tlsIntermediateCerts)) { + for (let i = 0; i < mspConfig.tlsIntermediateCerts.length; i++) { + mspConfig.tlsIntermediateCerts[i] = Buffer.from( + mspConfig.tlsIntermediateCerts[i] + ).toString('base64') + } + } else if (mspConfig.tlsIntermediateCerts.length === 0) { + mspConfig.tlsIntermediateCerts = [] + } else { + mspConfig.tlsIntermediateCerts = [ + Buffer.from(mspConfig.tlsIntermediateCerts).toString('base64') + ] + } + mspConfig.tls_intermediate_certs = mspConfig.tlsIntermediateCerts + delete mspConfig.tlsIntermediateCerts + orgMspConfig[mspId] = mspConfig + } + }) + return orgMspConfig +} + +async function fabricHelper({ + channel, + contractName, + connProfilePath, + networkName, + mspId = global.__DEFAULT_MSPID__, + logger = console, + discoveryEnabled = true, + userString = '', + userPwd = '', + registerUser = true +}: { + channel: string + contractName: string + connProfilePath: string + networkName: string + mspId?: string + discoveryEnabled?: boolean + logger?: any + userString?: string + userPwd?: string + registerUser?: boolean +}): Promise<{ gateway: Gateway; contract: Contract; wallet: any }> { + // load the network configuration + const ccpPath = path.resolve(__dirname, connProfilePath) + const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) + // Create a new file system based wallet for managing identities. + // const walletPath = process.env.WALLET_PATH + // ? process.env.WALLET_PATH + // : path.join(__dirname, '../', `wallet-${networkName}`) + + if (!userString) { + userString = `user1` + userPwd = `user1pw` + } + + const wallet = await walletSetup(networkName, ccp, mspId, userString, userPwd, false, false, registerUser, logger) + // Check to see if we've already enrolled the user. + const identity = await wallet.get(userString) + if (!identity) { + logger.info( + `An identity for the user "${userString}" does not exist in the wallet` + ) + logger.info('Run the registerUser.ts application before retrying') + } + // Create a new gateway for connecting to our peer node. + const gateway = new Gateway() + await gateway.connect(ccp, { + wallet, + identity: identity, + discovery: { + enabled: discoveryEnabled, + asLocalhost: process.env.LOCAL === 'false' ? false : true + } + }) + const network = await gateway.getNetwork(channel) + // Get the contract from the network. + const contract = network.getContract(contractName) + return { gateway, contract, wallet } +} + +async function query( + invocationSpec: InvocationSpec, + connProfilePath: string, + networkName: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console, + userString = '', + registerUser = true +): Promise { + logger.debug('Running invoke on fabric network') + try { + logger.debug( + `QUERY: ${JSON.stringify( + invocationSpec + )} connProfilePath: ${connProfilePath} networkName ${networkName} ` + ) + const { contract, gateway } = await fabricHelper({ + channel: invocationSpec.channel, + contractName: invocationSpec.contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: mspId, + logger: logger, + userString: userString, + registerUser: registerUser + }) + const read = await contract.evaluateTransaction(invocationSpec.ccFunc, ...invocationSpec.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`State From Network:`, state) + } else { + logger.debug(`No State from network`) + } + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + logger.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +async function invoke( + invocationSpec: InvocationSpec, + connProfilePath: string, + networkName: string, + mspId = global.__DEFAULT_MSPID__, + logger: any = console, + userString = '', + registerUser = true +): Promise { + logger.debug('Running invoke on fabric network') + try { + const { contract, gateway } = await fabricHelper({ + channel: invocationSpec.channel, + contractName: invocationSpec.contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: mspId, + logger: logger, + userString: userString, + registerUser: registerUser + }) + logger.debug( + `CCFunc: ${invocationSpec.ccFunc} 'CCArgs: ${JSON.stringify(invocationSpec.args)}` + ) + const read = await contract.submitTransaction(invocationSpec.ccFunc, ...invocationSpec.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +const getKeyAndCertForRemoteRequestbyUserName = async ( + wallet: any, + username: string +): Promise<{ key: ICryptoKey; cert: any }> => { + if (!wallet) { + throw new Error('No wallet passed') + } + if (!username) { + throw new Error('No username passed') + } + const identity = await wallet.get(username) + if (!identity) { + throw new Error( + 'Identity for username ' + username + ' not present in wallet' + ) + } + // Assume the identity is of type 'fabric-network.X509Identity' + const privKey = Utils.newCryptoSuite().createKeyFromRaw( + identity.credentials.privateKey + ) + return { key: privKey, cert: identity.credentials.certificate } +} + +const getWalletForNetwork = async ( + networkName: string, +) => { + const walletPath = process.env.WALLET_PATH + ? process.env.WALLET_PATH + : path.join(__dirname, '../', `wallet-${networkName}`) + + const wallet = await Wallets.newFileSystemWallet(walletPath) + return wallet +} + + +export { + getUserCertBase64, + walletSetup, + invoke, + query, + enrollAndRecordWalletIdentity, + fabricHelper, + generateMembership, + generateAccessControl, + getKeyAndCertForRemoteRequestbyUserName, + getCredentialPath, + getCurrentNetworkCredentialPath, + generateVerificationPolicy +} diff --git a/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts b/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts new file mode 100644 index 0000000000..624164d8be --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts @@ -0,0 +1,764 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { getKeyAndCertForRemoteRequestbyUserName, fabricHelper, invoke, query, InvocationSpec } from './fabric-functions' +import { AssetPledge } from "@hyperledger/cacti-weaver-protos-js/common/asset_transfer_pb" +import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric' +import * as crypto from 'crypto' +import { promisify } from 'util' +import * as fs from 'fs' +import * as path from 'path' +import * as dotenv from 'dotenv' +import logger from './logger' +dotenv.config({ path: path.resolve(__dirname, '../../.env') }) + + +// UPDATE Following if new env variable or config variable is added. +// Valid keys for .env +const validKeys = [ + 'DEFAULT_CHANNEL', + 'DEFAULT_CHAINCODE', + 'MEMBER_CREDENTIAL_FOLDER', + 'LOCAL', + 'DEFAULT_APPLICATION_CHAINCODE', + 'CONFIG_PATH', + 'REMOTE_CONFIG_PATH', + 'CHAINCODE_PATH' +] +// Valid keys for config +const configKeys = ['connProfilePath', 'relayEndpoint', 'mspId', 'channelName', 'chaincode', 'aclPolicyPrincipalType'] + +const signMessage = (message, privateKey) => { + const sign = crypto.createSign('sha256') + sign.write(message) + sign.end() + return sign.sign(privateKey) +} + +// Basic function to add assets to network, it assumes function is CreateAsset +// TODO: Pass function name as parameter +const addAssets = ({ + dataFilePath, + networkName, + connProfilePath, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + channelName, + contractName, + ccFunc, + ccType, + logger +}: { + dataFilePath: string + networkName: string + connProfilePath: string + invocationSpec?: InvocationSpec + mspId?: string + channelName?: string + contractName?: string + ccFunc?: string + ccType: string + logger?: any +}): void => { + const filepath = path.resolve(dataFilePath) + const data = JSON.parse(fs.readFileSync(filepath).toString()) + const valuesList = Object.entries(data) + valuesList.forEach(async (item: [string, string]) => { + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: channelName, + contractName: contractName + ? contractName + : 'simpleasset', + ccFunc: '', + args: [] + } + + const { gateway, contract, wallet } = await fabricHelper({ + channel: channelName, + contractName: contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: mspId, + userString: item[1]['owner'], + registerUser: false + }) + const userId = await wallet.get(item[1]['owner']) + const userCert = Buffer.from((userId).credentials.certificate).toString('base64') + + if (ccType == 'bond') { + currentQuery.ccFunc = 'CreateAsset' + currentQuery.args = [...currentQuery.args, item[1]['assetType'], item[1]['id'], userCert, item[1]['issuer'], item[1]['facevalue'], item[1]['maturitydate']] + } else if (ccType == 'token') { + currentQuery.ccFunc = 'IssueTokenAssets' + currentQuery.args = [...currentQuery.args, item[1]['tokenassettype'], item[1]['numunits'], userCert] + } else { + throw new Error(`Unrecognized asset category: ${ccType}`) + } + console.log(currentQuery) + try { + const read = await contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } + }) +} + + +// Basic function to pledge an asset in one network to another, it assumes function is PledgeAsset +// TODO: Pass function name as parameter +const pledgeAsset = async ({ + dataFilePath, + sourceNetworkName, + destNetworkName, + recipient, + expirySecs, + connProfilePath, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + channelName, + contractName, + ccFunc, + ccType, + assetOwner, + assetRef, + assetUnits, + logger +}: { + dataFilePath: string + sourceNetworkName: string + destNetworkName: string + recipient: string + expirySecs: number + connProfilePath: string + invocationSpec?: InvocationSpec + mspId?: string + channelName?: string + contractName?: string + ccFunc?: string + ccType: string + assetOwner: string + assetRef: string + assetUnits: number + logger?: any +}): Promise => { + const filepath = path.resolve(dataFilePath) + const data = JSON.parse(fs.readFileSync(filepath).toString()) + let item + if (assetRef) { + item = data[assetRef] + if (!item) { + throw new Error(`Cannot find asset ref ${assetRef} in file ${filepath}`) + } + } else if (assetOwner) { + item = data[assetOwner] + if (!item) { + throw new Error(`Cannot find asset owner ${assetOwner} in file ${filepath}`) + } + } else { + throw new Error(`Neither asset owner nor reference is supplied`) + } + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: channelName, + contractName: contractName + ? contractName + : 'simpleasset', + ccFunc: '', + args: [] + } + + const { gateway, contract, wallet } = await fabricHelper({ + channel: channelName, + contractName: contractName, + connProfilePath: connProfilePath, + networkName: sourceNetworkName, + mspId: mspId, + userString: item['owner'], + registerUser: false + }) + const recipientCert = getUserCertFromFile(recipient, destNetworkName) + const expirationTime = (Math.floor(Date.now()/1000 + expirySecs)).toString() + + if (ccType == 'bond') { + currentQuery.ccFunc = 'PledgeAsset' + currentQuery.args = [...currentQuery.args, item['assetType'], item['id'], destNetworkName, recipientCert, expirationTime] + } else if (ccType == 'token') { + currentQuery.ccFunc = 'PledgeTokenAsset' + currentQuery.args = [...currentQuery.args, item['tokenassettype'], '' + assetUnits, destNetworkName, recipientCert, expirationTime] + } else { + throw new Error(`Unrecognized/unsupported asset category: ${ccType}`) + } + console.log(currentQuery) + try { + const read = await contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +// Used to obtain remote network user certificate from '${networkId}_UsersAndCerts.json' file. +// This is called during Pledge to get the recipientCert, and during Claim to get the pledgerCert. +const getUserCertFromFile = ( + remoteUser: string, + remoteNetworkId: string +) => { + const usersAndCertsFile = remoteNetworkId + '_UsersAndCerts.json' + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, '..') + : path.join(__dirname, '../data', 'credentials', '..') + try { + const dirPath = path.resolve(credentialsPath, 'remoteNetworkUsers') + const filepath = path.resolve(dirPath, usersAndCertsFile) + const usersAndCertsJSON = JSON.parse(fs.readFileSync(filepath).toString()) + logger.debug(`credentialsPath: ${credentialsPath} and usersAndCertsFile: ${usersAndCertsFile}`) + + if (!usersAndCertsJSON[remoteUser]) { + logger.error( + `User: ${remoteUser} does not exist in the file ${usersAndCertsFile}.` + ) + return '' + } + logger.debug(`remoteUser: ${remoteUser} and certificate: ${usersAndCertsJSON[remoteUser]}`) + return usersAndCertsJSON[remoteUser] + } catch (err) { + logger.error(`User: ${remoteUser} does not exist in the file ${usersAndCertsFile}.`) + return '' + } +} + +// Used to store the network user certificate to the file '${networkId}_UsersAndCerts.json'. +// This is used during Pledge to get the recipientCert, and during Claim to get the pledgerCert. +const saveUserCertToFile = ( + remoteUser: string, + remoteNetworkId: string +) => { + const usersAndCertsFile = remoteNetworkId + '_UsersAndCerts.json' + let usersAndCertsJSON = {} + const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER + ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, '..') + : path.join(__dirname, '../data', 'credentials', '..') + // Don't create the directory 'remoteNetworkUsers' inside 'data/credentials' since each entry there represents + // a network. Instead, create this directory inside 'data' itself. + try { + const dirPath = path.resolve(credentialsPath, 'remoteNetworkUsers') + const filepath = path.resolve(dirPath, usersAndCertsFile) + logger.debug(`credentialsPath: ${credentialsPath} and usersAndCertsFile: ${usersAndCertsFile}`) + + if (!fs.existsSync(dirPath)) { + logger.debug(`Creating directory ${dirPath}`) + fs.mkdirSync(dirPath, { recursive: true }) + } + + if (fs.existsSync(filepath)) { + logger.debug(`Reading contents of the file ${filepath}`) + usersAndCertsJSON = JSON.parse(fs.readFileSync(filepath).toString()) + } + + const remoteUserId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + remoteNetworkId + '/' + remoteUser + '.id').toString()) + const remoteUserCertBase64 = Buffer.from(remoteUserId.credentials.certificate).toString('base64') + + usersAndCertsJSON[remoteUser] = remoteUserCertBase64 + fs.writeFileSync( + path.resolve(filepath), + JSON.stringify(usersAndCertsJSON) + ) + } catch (err) { + logger.error(`User: ${remoteUser} certificate cannot be saved to the file ${usersAndCertsFile}.`) + } +} + +// Basic function to query asset pledge details from a network, it assumes function is GetAssetPledgeStatus +// TODO: Pass function name as parameter +const getAssetPledgeDetails = async ({ + sourceNetworkName, + pledger, + pledgerCert, + destNetworkName, + recipient, + recipientCert, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + ccFunc, + pledgeId, + logger +}: { + sourceNetworkName: string + pledger: string + pledgerCert: string + destNetworkName: string + recipient: string + recipientCert: string + invocationSpec?: InvocationSpec + mspId?: string + ccFunc?: string + pledgeId: string + logger?: any +}): Promise => { + const netConfig = getNetworkConfig(sourceNetworkName) + + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: netConfig.channelName, + contractName: netConfig.chaincode + ? netConfig.chaincode + : 'simpleasset', + ccFunc: '', + args: [] + } + + const { gateway, contract, wallet } = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: sourceNetworkName, + mspId: netConfig.mspId, + userString: pledger, + registerUser: false + }) + if (!pledgerCert) { + const pledgerId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + sourceNetworkName + '/' + pledger + '.id').toString()) + pledgerCert = Buffer.from(pledgerId.credentials.certificate).toString('base64') + } + if (!recipientCert) { + const recipientId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + destNetworkName + '/' + recipient + '.id').toString()) + recipientCert = Buffer.from(recipientId.credentials.certificate).toString('base64') + } + + currentQuery.ccFunc = 'GetAssetPledgeStatus' + currentQuery.args = [...currentQuery.args, pledgeId, pledgerCert, destNetworkName, recipientCert] + console.log(currentQuery) + try { + const read = await contract.evaluateTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + } else { + logger.debug('No Response from network') + } + + // Disconnect from the gateway. + await gateway.disconnect() + return state + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } +} + +// Basic function to query asset pledge details from a network, it assumes function is GetAssetPledgeDetails +// TODO: Pass function name as parameter +const getLocalAssetPledgeDetails = async ({ + sourceNetworkName, + pledgeId, + caller, + ccType, + ccFunc, + logger +}: { + sourceNetworkName: string + pledgeId: string + caller: string + ccType?: string + ccFunc?: string + logger?: any +}): Promise => { + const netConfig = getNetworkConfig(sourceNetworkName) + + const currentQuery = { + channel: netConfig.channelName, + contractName: netConfig.chaincode + ? netConfig.chaincode + : 'simpleasset', + ccFunc: '', + args: [] + } + + if (ccFunc) { + currentQuery.ccFunc = ccFunc + } else if (ccType && ccType == 'token') { + currentQuery.ccFunc = 'GetTokenAssetPledgeDetails' + } else { + currentQuery.ccFunc = 'GetAssetPledgeDetails' + } + currentQuery.args = [...currentQuery.args, pledgeId] + console.log(currentQuery) + try { + const pledgeDetails = await query(currentQuery, + netConfig.connProfilePath, + sourceNetworkName, + netConfig.mspId, + logger, + caller, + false + ) + const pledgeDetailBytes = Buffer.from(pledgeDetails, 'base64') + const pledgeDetailsProto = AssetPledge.deserializeBinary(pledgeDetailBytes) + return pledgeDetailsProto + } catch (error) { + console.error(`Failed to get pledge details: ${error}`) + throw new Error(error) + } +} + +// Basic function to add data to network, it assumes function is Create +// TODO: Pass function name as parameter +const addData = ({ + filename, + networkName, + connProfilePath, + invocationSpec, + mspId = global.__DEFAULT_MSPID__, + logger +}: { + filename: string + networkName: string + connProfilePath: string + invocationSpec?: InvocationSpec + mspId?: string + logger?: any +}): void => { + const filepath = path.resolve(__dirname, '..', 'data', filename) + const data = JSON.parse(fs.readFileSync(filepath).toString()) + const valuesList = Object.entries(data) + valuesList.forEach((item: [string, string]) => { + const currentQuery = invocationSpec + ? invocationSpec + : { + channel: process.env.DEFAULT_CHANNEL + ? process.env.DEFAULT_CHANNEL + : 'mychannel', + contractName: process.env.DEFAULT_APPLICATION_CHAINCODE + ? process.env.DEFAULT_APPLICATION_CHAINCODE + : 'simplestate', + ccFunc: process.env.DEFAULT_APPLICATION_FUNC + ? process.env.DEFAULT_APPLICATION_FUNC + : 'Create', + args: [] + } + currentQuery.args = [...currentQuery.args, item[0], item[1]] + invoke(currentQuery, connProfilePath, networkName, mspId, logger) + }) +} + +// A better way to handle errors for promises +function handlePromise(promise: Promise): Promise<[T?, Error?]> { + const result: Promise<[T?, Error?]> = promise + .then(data => { + const response: [T?, Error?] = [data, undefined] + return response + }) + .catch(error => Promise.resolve([undefined, error])) + return result +} + +// Necessary until gRPC provides a native async friendly solution https://github.com/grpc/grpc-node/issues/54 +function promisifyAll(client): any { + const to = {} + for (const k in client) { + if (typeof client[k] != 'function') continue + to[k] = promisify(client[k].bind(client)) + } + return to +} + +const readJSONFromFile = (jsonfile, logger = console) => { + let data = null + const filepath = path.resolve(jsonfile) + logger.debug('jsonfile is ' + jsonfile) + logger.debug('filepath is ' + filepath) + + try { + const contents = fs.readFileSync(filepath).toString() + logger.debug('contents ' + contents) + data = JSON.parse(contents) + logger.debug('data - ' + JSON.stringify(data)) + } catch (e) { + logger.debug('Error ' + e.message + ' while parsing JSON config file') + throw e + } + return data +} + +// Used for getting network configuration from config.json file. +const getNetworkConfig = ( + networkId: string +): { relayEndpoint?: string; connProfilePath: string; username?: string; mspId?:string; aclPolicyPrincipalType?: string; channelName?: string; chaincode?: string } => { + const configPath = process.env.CONFIG_PATH + ? path.join(process.env.CONFIG_PATH) + : path.join(__dirname, '../../config.json') + try { + const configJSON = JSON.parse(fs.readFileSync(configPath).toString()) + if (!configJSON[networkId]) { + logger.error( + `Network: ${networkId} does not exist in the config.json file` + ) + return { relayEndpoint: '', connProfilePath: '', username: '', mspId: '', aclPolicyPrincipalType: '', channelName: '', chaincode: '' } + } + return configJSON[networkId] + } catch (err) { + logger.error(`Network: ${networkId} does not exist in the config.json file`) + return { relayEndpoint: '', connProfilePath: '', username: '', mspId: '', aclPolicyPrincipalType: '', channelName: '', chaincode: '' } + } +} + +// Used for getting network configuration from config.json file. +const getChaincodeConfig = ( + chaincodeId: string, + chaincodeFunc: string +): { args: Array; replaceIndices: Array } => { + const ccPath = process.env.CHAINCODE_PATH + ? path.join(process.env.CHAINCODE_PATH) + : path.join(__dirname, '../../chaincode.json') + try { + const ccJSON = JSON.parse(fs.readFileSync(ccPath).toString()) + if (!ccJSON[chaincodeId]) { + logger.error( + `Chaincode: ${chaincodeId} does not exist in the chaincode.json file` + ) + return { args: [], replaceIndices: [] } + } + if (!ccJSON[chaincodeId][chaincodeFunc]) { + logger.error( + `Chaincode: ${chaincodeId} does not have a ${chaincodeFunc} function attribute in the chaincode.json file` + ) + return { args: [], replaceIndices: [] } + } + return ccJSON[chaincodeId][chaincodeFunc] + } catch (err) { + logger.error(`Chaincode: ${chaincodeId} does not exist in the chaincode.json file`) + return { args: [], replaceIndices: [] } + } +} + +// Update view address if needed +const generateViewAddress = async ( + viewAddress: string, + sourceNetwork: string, + destNetwork: string, + logger?: any +): Promise => { + if (!viewAddress || viewAddress.length === 0) { + throw new Error('Empty view address') + } + if (viewAddress.indexOf('#') >= 0) { + return viewAddress + } + if (viewAddress.indexOf('GetAssetClaimStatus') >= 0 || viewAddress.indexOf('GetTokenAssetClaimStatus') >= 0) { + // Get asset pledge details + let ccFunc + if (viewAddress.indexOf('GetAssetClaimStatus') >= 0) { + ccFunc = 'GetAssetClaimStatus' + } else { + ccFunc = 'GetTokenAssetClaimStatus' + } + const addressParts = viewAddress.substring(viewAddress.indexOf(ccFunc) + ccFunc.length + 1).split(':') + if (addressParts.length != 6) { + throw new Error(`Expected 6 arguments for ${ccFunc}; found ${addressParts.length}`) + } + if (addressParts[5] != sourceNetwork) { + throw new Error(`Passed source network ID ${sourceNetwork} does not match last chaincode argument in view address ${addressParts[5]}`) + } + const pledgeDetails = await getAssetPledgeDetails({ + sourceNetworkName: addressParts[5], + pledger: '', + pledgerCert: addressParts[4], + destNetworkName: destNetwork, + recipient: '', + recipientCert: addressParts[3], + pledgeId: addressParts[0], + logger: logger + }) + return viewAddress + ':' + deserializeAssetPledge(pledgeDetails).getExpirytimesecs() + } else { + return viewAddress + } +} + +function deserializeAssetPledge(pledgeDetails) { + const pledgeDetailBytes = Buffer.from(pledgeDetails, 'base64') + const pledgeDetailsProto = AssetPledge.deserializeBinary(pledgeDetailBytes) + return pledgeDetailsProto +} + +// Used for creating view address for interop call using remote-network-config.json +const generateViewAddressFromRemoteConfig = ( + networkId: string, + funcName: string, + funcArgs: Array +): any => { + const configPath = process.env.REMOTE_CONFIG_PATH + ? path.join(process.env.REMOTE_CONFIG_PATH) + : path.join(__dirname, '../../remote-network-config.json') + try { + const configJSON = JSON.parse(fs.readFileSync(configPath).toString()) + if (!configJSON[networkId]) { + logger.error( + `Error: ${networkId} does not exist in the remote-network-config.json file` + ) + throw new Error(`Error: ${networkId} does not exist in the remote-network-config.json file`) + } + + const remoteNetConfig = configJSON[networkId] + let address = remoteNetConfig.relayEndpoint + '/' + networkId + if (remoteNetConfig.type == "fabric") { + address = address + '/' + remoteNetConfig.channelName + ':' + + remoteNetConfig.chaincode + ':' + funcName + ':' + funcArgs.join(':') + } else if (remoteNetConfig.type == "corda") { + address = address + '/' + remoteNetConfig.partyEndPoint + '#' + + remoteNetConfig.flowPackage + "." + funcName + ":" + funcArgs.join(':') + } else { + logger.error(`Error: remote network ${remoteNetConfig.type} not supported.`) + throw new Error(`Error: remote network ${remoteNetConfig.type} not supported.`) + } + console.log(`Interop query, funcName: ${funcName} \n funcArgs: ${funcArgs} \n and address: ${address}`) + + return address + } catch (err) { + logger.error(`Error: ${err}`) + throw new Error(err) + } +} + + +// Used for creating view address for interop call using remote-network-config.json +const interopHelper = async ( + networkName: string, + viewAddress: string, + appChaincodeId: string, + applicationFunction: string, + applicationArgs: Array, + replaceIndices: Array, + options: any, // For TLS +): Promise => { + const netConfig = getNetworkConfig(networkName) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + throw new Error(`No valid config entry found for ${networkName}`) + } + + const { gateway, wallet, contract } = await fabricHelper({ + channel: netConfig.channelName, + contractName: process.env.DEFAULT_CHAINCODE ? process.env.DEFAULT_CHAINCODE : 'interop', + connProfilePath: netConfig.connProfilePath, + networkName, + mspId: netConfig.mspId, + logger, + discoveryEnabled: true, + userString: options['user'] + }) + + const [keyCert, keyCertError] = await handlePromise( + getKeyAndCertForRemoteRequestbyUserName(wallet, options['user']) + ) + if (keyCertError) { + throw new Error(`Error getting key and cert ${keyCertError}`) + } + logger.info(`Starting Interop Query`) + + let relayTlsCAFiles = [] + if (options['relay-tls-ca-files']) { + relayTlsCAFiles = options['relay-tls-ca-files'].split(':') + } + try { + const invokeObject = { + channel: netConfig.channelName, + ccFunc: applicationFunction, + ccArgs: applicationArgs, + contractName: appChaincodeId + } + console.log(invokeObject) + const interopFlowResponse = await InteroperableHelper.interopFlow( + //@ts-ignore this comment can be removed after using published version of interop-sdk + contract, + networkName, + invokeObject, + netConfig.mspId, + netConfig.relayEndpoint, + replaceIndices, + [{ + address: viewAddress, + Sign: true + }], + keyCert, + [], + false, + options['relay-tls'] === 'true', + relayTlsCAFiles, + options['e2e-confidentiality'] === 'true', + gateway + ) + logger.info( + `View from remote network: ${JSON.stringify( + interopFlowResponse.views[0].toObject() + )}. Interop Flow result: ${interopFlowResponse.result || 'successful'}` + ) + logger.debug(`ViewB64: ${Buffer.from(interopFlowResponse.views[0].serializeBinary()).toString('base64')}`) + const remoteValue = (options['e2e-confidentiality'] === 'true' ? + InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0], keyCert.key.toBytes()) : + InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0]) + ) + if (remoteValue.contents) { + logger.debug(`ViewB64Contents: ${Buffer.from(remoteValue.contents).toString('base64')}`) + } + logger.info( + `Called Function ${applicationFunction}. With Args: ${invokeObject.ccArgs} ${remoteValue.data}` + ) + await gateway.disconnect() + return remoteValue.data + } catch (e) { + logger.error(`Error verifying and storing state`) + logger.error(`Error verifying and storing state: ${e}`) + return "" + } +} + + + +export { + addData, + handlePromise, + promisifyAll, + readJSONFromFile, + signMessage, + getNetworkConfig, + getUserCertFromFile, + saveUserCertToFile, + getChaincodeConfig, + validKeys, + configKeys, + addAssets, + pledgeAsset, + getAssetPledgeDetails, + getLocalAssetPledgeDetails, + generateViewAddress, + generateViewAddressFromRemoteConfig, + interopHelper +} diff --git a/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts b/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts new file mode 100644 index 0000000000..b85bbc1db6 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts @@ -0,0 +1,230 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as fs from 'fs' +import * as path from 'path' +import { + invoke, + getCurrentNetworkCredentialPath, + getCredentialPath, + fabricHelper +} from '../fabric-functions' +import { handlePromise, getNetworkConfig } from '../helpers' +import { MembershipManager } from '@hyperledger/cacti-weaver-sdk-fabric' + +const helperInvoke = async (userId, ccFunc, ccArg, ...args) => { + const [contractName, channelName, connProfilePath, networkName, logger] = args + const [invokeResponse, invokeError] = await handlePromise( + invoke( + { + contractName, + channel: channelName, + ccFunc: ccFunc, + args: [ccArg] + }, + connProfilePath, + networkName, + global.__DEFAULT_MSPID__, + logger, + userId, + (userId === '') + ) + ) + logger.debug(`${ccFunc} Invoke ${JSON.stringify(invokeResponse)}`) + if (invokeError) { + logger.error(`${ccFunc} Invoke Error: ${ccFunc}: ${ccArg}`) + throw new Error(`${ccFunc} Invoke Error ${invokeError}`) + } else { + logger.info(`Successfully invoked ${ccFunc}`) + } +} + +const configureNetwork = async (mainNetwork: string, members: Array = [global.__DEFAULT_MSPID__], logger: any = console, iinAgent: boolean = false) => { + const networkEnv = getNetworkConfig(mainNetwork) + logger.debug(`NetworkEnv: ${JSON.stringify(networkEnv)}`) + if (!networkEnv.relayEndpoint || !networkEnv.connProfilePath) { + logger.error( + 'Please use a valid --local-network. If valid network please check if your environment variables are configured properly' + ) + return + } + + const credentialFolderPath = getCredentialPath() + const networkFolders = fs + .readdirSync(credentialFolderPath, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .map(item => item.name) + // Reorder the array so that the local network is the first element + // We need to record local membership before recording other networks' memberships + networkFolders.splice(networkFolders.indexOf(mainNetwork), 1) + networkFolders.splice(0, 0, mainNetwork) + + for (const index in networkFolders) { + const network = networkFolders[index] + if (network === mainNetwork) { + // A network needs to load/record only other networks' credentials + await loadLocalHelper( + networkEnv.connProfilePath, + mainNetwork, + process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', + process.env.DEFAULT_CHAINCODE + ? process.env.DEFAULT_CHAINCODE + : 'interop', + members, + logger + ) + continue; + } + const accessControlPath = path.join( + getCurrentNetworkCredentialPath(network), + 'access-control.json' + ) + let membershipPath = "" + if (!network.startsWith('network')) { + membershipPath = path.join( + getCurrentNetworkCredentialPath(network), + 'membership.json' + ) + } else if (iinAgent) { + membershipPath = path.join( + getCurrentNetworkCredentialPath(network), + 'attested-membership-' + mainNetwork + '.proto.serialized' + ) + } + const verificationPolicyPath = path.join( + getCurrentNetworkCredentialPath(network), + 'verification-policy.json' + ) + if ( + !fs.existsSync(accessControlPath) || + !fs.existsSync(verificationPolicyPath) || + (membershipPath !== "" && !fs.existsSync(membershipPath)) + ) { + logger.error(`Missing credential file for network: ${network}`) + } else { + await configureNetworkHelper( + networkEnv.connProfilePath, + mainNetwork, + process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', + process.env.DEFAULT_CHAINCODE + ? process.env.DEFAULT_CHAINCODE + : 'interop', + network, + accessControlPath, + membershipPath, + verificationPolicyPath, + logger, + iinAgent + ) + } + } +} + +const loadLocalHelper = async ( + connProfilePath: string, + networkName: string, + channelName: string, + contractName: string, + members: Array, + logger: any = console +): Promise => { + //const localMembership = Buffer.from(fs.readFileSync(localMembershipPath)).toString() + const { gateway } = await fabricHelper({ + channel: channelName, + contractName: contractName, + connProfilePath: connProfilePath, + networkName: networkName, + mspId: global.__DEFAULT_MSPID__, + userString: 'networkadmin', + registerUser: false + }) + try { + const response = await MembershipManager.createLocalMembership(gateway, members, networkName, channelName, contractName) + logger.info('CreateLocalMembership Successful.') + } catch (e) { + logger.error(e) + logger.info('CreateLocalMembership attempting Update') + const response = await MembershipManager.updateLocalMembership(gateway, members, networkName, channelName, contractName) + logger.info('Update Local Memebrship response: success: ', response) + } +} + +const configureNetworkHelper = async ( + connProfilePath: string, + networkName: string, + channelName: string, + contractName: string, + targetNetwork: string, + accessControlPath: string, + membershipPath: string, + verificationPolicyPath: string, + logger: any = console, + iinAgent: boolean = false +): Promise => { + logger.info(`Target Network: ${targetNetwork}`) + const accessControl = Buffer.from( + fs.readFileSync(accessControlPath) + ).toString() + + const verificationPolicy = Buffer.from( + fs.readFileSync(verificationPolicyPath) + ).toString() + + const helperInvokeArgs = [ + contractName, + channelName, + connProfilePath, + networkName, + logger + ] + + const adminUser = 'networkadmin' + + try { + await helperInvoke( + adminUser, + 'CreateAccessControlPolicy', + accessControl, + ...helperInvokeArgs + ) + } catch (e) { + logger.info('CreateAccessControlPolicy attempting Update') + await helperInvoke( + adminUser, + 'UpdateAccessControlPolicy', + accessControl, + ...helperInvokeArgs + ) + } + try { + await helperInvoke( + adminUser, + 'CreateVerificationPolicy', + verificationPolicy, + ...helperInvokeArgs + ) + } catch (e) { + logger.info('CreateVerificationPolicy attempting Update') + await helperInvoke( + adminUser, + 'UpdateVerificationPolicy', + verificationPolicy, + ...helperInvokeArgs + ) + } + if (iinAgent || !targetNetwork.startsWith('network')) { + const membership = Buffer.from(fs.readFileSync(membershipPath)).toString() + const memberRecordingUser = iinAgent ? 'iinagent': adminUser // HACK until we add IIN Agents for Corda networks + try { + await helperInvoke(memberRecordingUser, 'CreateMembership', membership, ...helperInvokeArgs) + } catch (e) { + logger.info('CreateMembership attempting Update') + await helperInvoke(memberRecordingUser, 'UpdateMembership', membership, ...helperInvokeArgs) + } + } +} + +export { configureNetworkHelper, configureNetwork } diff --git a/weaver/core/drivers/fabric-driver/server/helpers/logger.ts b/weaver/core/drivers/fabric-driver/server/helpers/logger.ts new file mode 100644 index 0000000000..7b14c5a377 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/helpers/logger.ts @@ -0,0 +1,29 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as winston from 'winston' +import * as path from 'path' +const { format, transports } = winston + +const logFormat = format.printf( + info => `${info.timestamp} ${info.level} [${info.label}]: ${info.message}` +) + +const logger = winston.createLogger({ + format: format.combine( + format.label({ label: path.basename(process.mainModule.filename) }), + format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), + format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] }) + ), + transports: [ + new transports.Console({ + format: format.combine(format.colorize(), logFormat) + }) + ], + exitOnError: false +}) + +export default logger diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts new file mode 100644 index 0000000000..a1c6c6ca1c --- /dev/null +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -0,0 +1,389 @@ +import satp_pb from '@hyperledger/cacti-weaver-protos-js/relay/satp_pb'; +import satp_grpc_pb from '@hyperledger/cacti-weaver-protos-js/relay/satp_grpc_pb'; +import driverPb from '@hyperledger/cacti-weaver-protos-js/driver/driver_pb'; +import logger from './logger'; +import { credentials } from '@grpc/grpc-js'; + +import { getNetworkConfig } from './helpers/helpers' +import { SatpAssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' + +import fs from 'fs'; +import path from 'path'; +import { fabricHelper } from './helpers/fabric-functions'; + +const DB_NAME: string = "driverdb"; +const DRIVER_ERROR_CONSTANTS = JSON.parse( + fs.readFileSync( + path.resolve(__dirname, '../constants/driver-error-constants.json'), + ).toString(), +); + +async function performLockHelper( + performLockRequest: driverPb.PerformLockRequest, + networkName: string +): Promise { + + // TODO: remove the hardcoded values + let performLockRequest2 = {}; + performLockRequest2['target-network'] = 'network1'; + performLockRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; + performLockRequest2['timeout-duration'] = parseInt('3600'); + performLockRequest2['locker'] = 'alice'; + performLockRequest2['recipient'] = 'bob'; + performLockRequest2['param'] = 'bond01:a05'; + + // Locker and recipient + const locker = performLockRequest2['locker']; + const recipient = performLockRequest2['recipient']; + let hashFn = performLockRequest2['hash_fn']; + let hashBase64 = performLockRequest2['hashBase64']; + const targetNetwork = performLockRequest2['target-network']; + + // Hash + let hash: HashFunctions.Hash + if (hashFn == 'SHA512') { + hash = new HashFunctions.SHA512() + } else { + hash = new HashFunctions.SHA256() + } + + if (hashBase64) { + hash.setSerializedHashBase64(hashBase64) + } + else { + logger.info(`No hash provided, using random preimage`) + } + + // Timeout + var timeout = 0, timeout2 = 0; + const currTime = Math.floor(Date.now() / 1000); + if (performLockRequest2['timeout-epoch']) { + let duration = performLockRequest2['timeout-epoch'] - currTime + timeout = performLockRequest2['timeout-epoch'] + timeout2 = performLockRequest2['timeout-epoch'] + duration + } + else if (performLockRequest2['timeout-duration']) { + timeout = currTime + performLockRequest2['timeout-duration'] + timeout2 = currTime + 2 * performLockRequest2['timeout-duration'] + } + + const params = performLockRequest2['param'].split(':') + const netConfig = getNetworkConfig(targetNetwork) + + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + console.error( + `Please use a valid --target-network. No valid environment found for ${targetNetwork} ` + ) + return + } + + const network = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: targetNetwork, + mspId: netConfig.mspId, + userString: locker + }) + + const lockerId = await network.wallet.get(locker) + const lockerCert = Buffer.from((lockerId).credentials.certificate).toString('base64') + const recipientId = await network.wallet.get(recipient) + const recipientCert = Buffer.from((recipientId).credentials.certificate).toString('base64') + + var funcToCall, asset + + if (performLockRequest2['fungible']) { + funcToCall = SatpAssetManager.createFungibleHTLC + asset = 'Fungible Asset' + } else { + funcToCall = SatpAssetManager.createHTLC + asset = 'Asset' + } + + console.info(`Asset Lock: Lock ${asset}:\n`); + try { + console.info(`Trying ${asset} Lock: ${params[0]}, ${params[1]} by ${locker} for ${recipient}`) + const res = await funcToCall(network.contract, + params[0], + params[1], + recipientCert, + hash, + timeout, + null) + if (!res.result) { + throw new Error() + } + console.info(`${asset} Locked with Contract Id: ${res.result}, preimage: ${res.hash.getPreimage()}, hashvalue: ${res.hash.getSerializedHashBase64()}`) + console.info('Asset has been locked successfully') + + } catch (error) { + console.error(`Could not Lock ${asset} in ${targetNetwork}`) + } + + await network.gateway.disconnect() + logger.info('Gateways disconnected.') + + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(performLockRequest.getSessionId()); + request.setStatus("Locked"); + client.sendAssetStatus(request, relayCallback); +} + +async function createAssetHelper( + createAssetRequest: driverPb.CreateAssetRequest, + networkName: string +): Promise { + + // TODO: remove the hardcoded values + let createAssetRequest2 = {}; + createAssetRequest2['target-network'] = 'network1'; + createAssetRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; + createAssetRequest2['timeout-duration'] = parseInt('3600'); + createAssetRequest2['owner'] = 'admin'; + createAssetRequest2['type'] = 'bond'; + createAssetRequest2['assetType'] = 'bond01'; + createAssetRequest2['id'] = 'a0demo'; + createAssetRequest2['issuer'] = 'admin'; + createAssetRequest2['facevalue'] = '300'; + createAssetRequest2['maturitydate'] = '05 May 48 00:00 MST'; + + const targetNetwork = createAssetRequest2['target-network']; + const owner = createAssetRequest2['owner']; + const ccType = createAssetRequest2['type']; + const assetType = createAssetRequest2['assetType']; + const id = createAssetRequest2['id']; + const issuer = createAssetRequest2['issuer']; + const facevalue = createAssetRequest2['facevalue']; + const maturitydate = createAssetRequest2['maturitydate']; + const tokenassettype = createAssetRequest2['tokenassettype']; + const numunits = createAssetRequest2['numunits']; + + const netConfig = getNetworkConfig(targetNetwork) + console.info(netConfig) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + console.error( + `Please use a valid --target-network. No valid environment found for ${targetNetwork} ` + ) + return + } + + const currentQuery = { + channel: netConfig.channelName, + contractName: netConfig.chaincode, + ccFunc: '', + args: [] + } + + const network = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: targetNetwork, + mspId: netConfig.mspId, + userString: owner, + registerUser: false + }) + + const userId = await network.wallet.get(owner) + const userCert = Buffer.from((userId).credentials.certificate).toString('base64') + + if (ccType == 'bond') { + currentQuery.ccFunc = 'CreateAsset' + currentQuery.args = [...currentQuery.args, assetType, id, userCert, issuer, facevalue, maturitydate] + } else if (ccType == 'token') { + currentQuery.ccFunc = 'IssueTokenAssets' + currentQuery.args = [...currentQuery.args, tokenassettype, numunits, userCert] + } else { + throw new Error(`Unrecognized asset category: ${ccType}`) + } + console.log(currentQuery) + + try { + console.info(`Trying creating the asset: type: ${ccType}, id: ${id}, by: ${owner}, facevalue: ${facevalue}, maturitydate: ${maturitydate}`) + const read = await network.contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) + const state = Buffer.from(read).toString() + if (state) { + logger.debug(`Response From Network: ${state}`) + console.info('Asset has been created successfully') + } else { + logger.debug('No Response from network') + } + } catch (error) { + console.error(`Failed to submit transaction: ${error}`) + throw new Error(error) + } + + await network.gateway.disconnect() + logger.info('Gateways disconnected.') + + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(createAssetRequest.getSessionId()); + request.setStatus("Created"); + client.sendAssetStatus(request, relayCallback); +} + +async function extinguishHelper( + extinguishRequest: driverPb.ExtinguishRequest, + networkName: string +): Promise { + + // TODO + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(extinguishRequest.getSessionId()); + request.setStatus("Extinguished"); + client.sendAssetStatus(request, relayCallback); +} + +async function assignAssetHelper( + assignAssetRequest: driverPb.AssignAssetRequest, + networkName: string +): Promise { + + // TODO: remove the hardcoded values + let assignAssetRequest2 = {}; + assignAssetRequest2['target-network'] = 'network1'; + assignAssetRequest2['hashBase64'] = 'ivHErp1x4bJDKuRo6L5bApO/DdoyD/dG0mAZrzLZEIs='; + assignAssetRequest2['timeout-duration'] = parseInt('3600'); + assignAssetRequest2['locker'] = 'admin'; + assignAssetRequest2['recipient'] = 'bob'; + assignAssetRequest2['fungible'] = false; + assignAssetRequest2['contract-id'] = 'abc01'; + assignAssetRequest2['hash_fn'] = ''; + assignAssetRequest2['secret'] = 'secrettext'; + assignAssetRequest2['param'] = 'bond01:a0demo'; + + const targetNetwork = assignAssetRequest2['target-network']; + const locker = assignAssetRequest2['locker']; + const recipient = assignAssetRequest2['recipient']; + const fungible = assignAssetRequest2['fungible']; + const hashFn = assignAssetRequest2['hash_fn']; + const secret = assignAssetRequest2['secret']; + + // Hash + let hash: HashFunctions.Hash + if (hashFn == 'SHA512') { + hash = new HashFunctions.SHA512() + } else { + hash = new HashFunctions.SHA256() + } + hash.setPreimage(secret) + + let contractId: string = null, params + if (assignAssetRequest2['contract-id']) { + contractId = assignAssetRequest2['contract-id'] + } + + params = assignAssetRequest2['param'].split(':') + + const netConfig = getNetworkConfig(targetNetwork) + if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { + console.error( + `Please use a valid --target-network. No valid environment found for ${targetNetwork} ` + ) + return + } + + const network = await fabricHelper({ + channel: netConfig.channelName, + contractName: netConfig.chaincode, + connProfilePath: netConfig.connProfilePath, + networkName: targetNetwork, + mspId: netConfig.mspId, + userString: recipient + }) + + var funcToCall = SatpAssetManager.assignAsset + var asset = assignAssetRequest2['param'] + + if (assignAssetRequest2['fungible']) { + // funcToCall = SatpAssetManager.claimFungibleAssetInHTLC + asset = 'Fungible Asset' + } + + if (fungible) { + try { + console.info(`Trying assigning the asset with contract id ${contractId}`) + + // TODO + } catch (error) { + console.error(`Could not assign ${asset} in ${targetNetwork}`) + throw new Error(`Could not assign ${asset} in ${targetNetwork}`) + } + } else { + try { + const lockerId = await network.wallet.get(locker) + const lockerCert = Buffer.from((lockerId).credentials.certificate).toString('base64') + + console.info(`Trying assign asset with params: ${params[0]}, ${params[1]} locked by ${locker} for ${recipient}`) + const res = await funcToCall(network.contract, + params[0], + params[1], + lockerCert, + hash) + if (!res) { + throw new Error() + } + console.info(`${asset} assigned complete: ${res}`) + console.info(`Asset ${asset} assign complete: ${res}`) + } catch (error) { + console.error(`Could not assign non-fungible ${asset} in ${targetNetwork}: ${error}`) + throw new Error(`Could not assign non-fungible ${asset} in ${targetNetwork}: ${error}`) + } + + await network.gateway.disconnect() + logger.info('Gateways disconnected.') + + const client = getRelayClientForAssetStatusResponse(); + const request = new satp_pb.SendAssetStatusRequest(); + request.setSessionId(assignAssetRequest.getSessionId()); + request.setStatus("Finalized"); + client.sendAssetStatus(request, relayCallback); + } +} + +function getRelayClientForAssetStatusResponse() { + let client: satp_grpc_pb.SATPClient; + if (process.env.RELAY_TLS === 'true') { + if (!process.env.RELAY_TLSCA_CERT_PATH || process.env.RELAY_TLSCA_CERT_PATH == "") { + client = new satp_grpc_pb.SATPClient( + process.env.RELAY_ENDPOINT, + credentials.createSsl() + ); + } else { + if (!(process.env.RELAY_TLSCA_CERT_PATH && fs.existsSync(process.env.RELAY_TLSCA_CERT_PATH))) { + throw new Error("Missing or invalid RELAY_TLSCA_CERT_PATH: " + process.env.RELAY_TLSCA_CERT_PATH); + } + const rootCert = fs.readFileSync(process.env.RELAY_TLSCA_CERT_PATH); + client = new satp_grpc_pb.SATPClient( + process.env.RELAY_ENDPOINT, + credentials.createSsl(rootCert) + ); + } + } else { + client = new satp_grpc_pb.SATPClient( + process.env.RELAY_ENDPOINT, + credentials.createInsecure() + ); + } + return client; +} + +// handle callback +function relayCallback(err: any, response: any) { + if (response) { + logger.info(`Relay Callback Response: ${JSON.stringify(response.toObject())}`); + } else if (err) { + logger.error(`Relay Callback Error: ${err}`); + } +} + +export { + performLockHelper, + createAssetHelper, + extinguishHelper, + assignAssetHelper +} diff --git a/weaver/core/drivers/fabric-driver/server/server.ts b/weaver/core/drivers/fabric-driver/server/server.ts index c645caece3..427307e149 100644 --- a/weaver/core/drivers/fabric-driver/server/server.ts +++ b/weaver/core/drivers/fabric-driver/server/server.ts @@ -19,6 +19,7 @@ import 'dotenv/config'; import { loadEventSubscriptionsFromStorage, monitorBlockForMissedEvents } from './listener' import { walletSetup } from './walletSetup'; import { subscribeEventHelper, unsubscribeEventHelper, signEventSubscriptionQuery, writeExternalStateHelper } from "./events" +import { performLockHelper, createAssetHelper, extinguishHelper, assignAssetHelper } from "./satp" import * as path from 'path'; import { handlePromise, relayCallback, getRelayClientForQueryResponse, getRelayClientForEventSubscription, delay } from './utils'; import { dbConnectionTest, eventSubscriptionTest } from "./tests" @@ -233,6 +234,91 @@ server.addService(driver_pb_grpc.DriverCommunicationService, { callback(null, ack_err_response); }); }, + performLock: (call: { request: driverPb.PerformLockRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + performLockHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully locked the asset'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, + createAsset: (call: { request: driverPb.CreateAssetRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + createAssetHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully created the asset'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, + extinguish: (call: { request: driverPb.ExtinguishRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + extinguishHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully extinguished the asset'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, + assignAsset: (call: { request: driverPb.AssignAssetRequest }, callback: (_: any, object: ack_pb.Ack) => void) => { + const requestId: string = call.request.getSessionId(); + + assignAssetHelper(call.request, process.env.NETWORK_NAME ? process.env.NETWORK_NAME : 'network1').then(() => { + const ack_response = new ack_pb.Ack(); + ack_response.setRequestId(requestId); + ack_response.setMessage('Successfully assigned the asset'); + ack_response.setStatus(ack_pb.Ack.STATUS.OK); + // gRPC response. + logger.info(`Responding to caller with Ack: ${JSON.stringify(ack_response.toObject())}`); + callback(null, ack_response); + }).catch((error) => { + const ack_err_response = new ack_pb.Ack(); + ack_err_response.setRequestId(requestId); + ack_err_response.setMessage(error.toString()); + ack_err_response.setStatus(ack_pb.Ack.STATUS.ERROR); + // gRPC response. + logger.info(`Responding to caller with error Ack: ${JSON.stringify(ack_err_response.toObject())}`); + callback(null, ack_err_response); + }); + }, + }); // Prepares required crypto material for communication with the fabric network diff --git a/weaver/core/relay/Cargo.lock b/weaver/core/relay/Cargo.lock index 1d5b2e3080..ed534ff613 100644 --- a/weaver/core/relay/Cargo.lock +++ b/weaver/core/relay/Cargo.lock @@ -85,7 +85,7 @@ checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes", "futures-util", "http", @@ -170,6 +170,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "bumpalo" version = "3.13.0" @@ -209,6 +215,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "colored" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +dependencies = [ + "is-terminal", + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "config" version = "0.11.0" @@ -644,6 +661,17 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix 0.38.9", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -681,7 +709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ "arrayvec", - "bitflags", + "bitflags 1.3.2", "cfg-if", "ryu", "static_assertions", @@ -705,6 +733,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" + [[package]] name = "listenfd" version = "1.0.1" @@ -863,7 +897,7 @@ version = "0.10.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "foreign-types", "libc", @@ -1104,7 +1138,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1113,7 +1147,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1140,6 +1174,7 @@ dependencies = [ "base64 0.20.0", "bincode", "cacti_weaver_protos_rs", + "colored", "config", "futures", "listenfd", @@ -1223,11 +1258,24 @@ version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.5", "windows-sys 0.48.0", ] @@ -1295,7 +1343,7 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -1464,7 +1512,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix", + "rustix 0.37.20", "windows-sys 0.48.0", ] diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index 123e42eec4..43fa28f188 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -39,6 +39,7 @@ reqwest = { version = "0.11.16", features = ["json"] } serde_json = "1.0.95" # cacti_weaver_protos_rs = "2.0.0-alpha.1" cacti_weaver_protos_rs = { path = "../../common/protos-rs/pkg" } +colored = {version="2.0.4"} [build-dependencies] tonic-build = "0.8.4" diff --git a/weaver/core/relay/config/Dummy_Relay.toml b/weaver/core/relay/config/Dummy_Relay.toml index 125d18af27..bacb83f1fa 100644 --- a/weaver/core/relay/config/Dummy_Relay.toml +++ b/weaver/core/relay/config/Dummy_Relay.toml @@ -53,6 +53,6 @@ tls=false tlsca_cert_path="credentials/fabric_ca_cert.pem" [drivers.Dummy] hostname="localhost" -port="9092" +port="9090" tls=false tlsca_cert_path="credentials/fabric_ca_cert.pem" diff --git a/weaver/core/relay/driver/driver.rs b/weaver/core/relay/driver/driver.rs index 3c8f25d4a0..661d8bd8ed 100644 --- a/weaver/core/relay/driver/driver.rs +++ b/weaver/core/relay/driver/driver.rs @@ -6,11 +6,13 @@ // Internal modules use weaverpb::common::ack::{ack, Ack}; -use weaverpb::common::query::Query; use weaverpb::common::events::EventSubscription; -use weaverpb::common::state::{view_payload, Meta, meta, ViewPayload, View}; -use weaverpb::driver::driver::driver_communication_server::{DriverCommunication, DriverCommunicationServer}; -use weaverpb::driver::driver::WriteExternalStateMessage; +use weaverpb::common::query::Query; +use weaverpb::common::state::{meta, view_payload, Meta, View, ViewPayload}; +use weaverpb::driver::driver::driver_communication_server::{ + DriverCommunication, DriverCommunicationServer, +}; +use weaverpb::driver::driver::{PerformLockRequest, WriteExternalStateMessage}; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; @@ -22,8 +24,10 @@ use std::net::ToSocketAddrs; use std::thread::sleep; use std::time; use tokio::sync::RwLock; -use tonic::transport::{Identity, Server, ServerTlsConfig, Certificate, Channel, ClientTlsConfig}; +use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity, Server, ServerTlsConfig}; use tonic::{Request, Response, Status}; +use weaverpb::relay::satp::satp_client::SatpClient; +use weaverpb::relay::satp::SendAssetStatusRequest; pub struct DriverCommunicationService { pub config_lock: RwLock, @@ -42,7 +46,7 @@ impl DriverCommunication for DriverCommunicationService { println!("Got a request from {:?}", request.remote_addr()); let query = request.into_inner().clone(); let request_id = query.request_id.to_string(); - + let relays_table = self .config_lock .read() @@ -52,7 +56,9 @@ impl DriverCommunication for DriverCommunicationService { let relay_uri = relays_table .get(&query.requesting_relay.to_string()) .expect("Requesting relay not found in config file relays table"); - let uri = relay_uri.clone().try_into::() + let uri = relay_uri + .clone() + .try_into::() .expect("Syntax for relays table in config file not correct"); let relay_port = uri.port.to_string(); @@ -60,7 +66,7 @@ impl DriverCommunication for DriverCommunicationService { let use_tls = uri.tls; let tlsca_cert_path = uri.tlsca_cert_path.to_string(); let client_addr = format!("http://{}:{}", relay_hostname, relay_port); - + if use_tls { let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); let ca = Certificate::from_pem(pem); @@ -69,8 +75,13 @@ impl DriverCommunication for DriverCommunicationService { .ca_certificate(ca) .domain_name(relay_hostname); - let channel = Channel::from_shared(client_addr.to_string()).unwrap() - .tls_config(tls).expect(&format!("Error in TLS configuration for client: {}", client_addr.to_string())) + let channel = Channel::from_shared(client_addr.to_string()) + .unwrap() + .tls_config(tls) + .expect(&format!( + "Error in TLS configuration for client: {}", + client_addr.to_string() + )) .connect() .await .unwrap(); @@ -99,8 +110,14 @@ impl DriverCommunication for DriverCommunicationService { return Ok(Response::new(reply)); } - async fn subscribe_event(&self, request: Request) -> Result, Status> { - println!("Driver: Got a event subscription request from {:?}", request.remote_addr()); + async fn subscribe_event( + &self, + request: Request, + ) -> Result, Status> { + println!( + "Driver: Got a event subscription request from {:?}", + request.remote_addr() + ); let into_inner = request.into_inner().clone(); let query = into_inner.query.clone().expect(""); let request_id = query.clone().request_id.to_string(); @@ -114,9 +131,11 @@ impl DriverCommunication for DriverCommunicationService { let relay_uri = relays_table .get(&query.requesting_relay.to_string()) .expect("Requesting relay not found in config file relays table"); - let uri = relay_uri.clone().try_into::() + let uri = relay_uri + .clone() + .try_into::() .expect("Syntax for relays table in config file not correct"); - + let relay_port = uri.port.to_string(); let relay_hostname = uri.hostname.to_string(); let use_tls = uri.tls; @@ -131,8 +150,13 @@ impl DriverCommunication for DriverCommunicationService { .ca_certificate(ca) .domain_name(relay_hostname); - let channel = Channel::from_shared(client_addr.to_string()).unwrap() - .tls_config(tls).expect(&format!("Error in TLS configuration for client: {}", client_addr.to_string())) + let channel = Channel::from_shared(client_addr.to_string()) + .unwrap() + .tls_config(tls) + .expect(&format!( + "Error in TLS configuration for client: {}", + client_addr.to_string() + )) .connect() .await .unwrap(); @@ -161,7 +185,10 @@ impl DriverCommunication for DriverCommunicationService { return Ok(Response::new(reply)); } - async fn request_signed_event_subscription_query(&self, request: Request) -> Result, Status> { + async fn request_signed_event_subscription_query( + &self, + request: Request, + ) -> Result, Status> { let received_query = request.into_inner().clone().query.expect("Err"); let signed_query: Query = Query { policy: received_query.policy, @@ -177,7 +204,10 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(signed_query)); } - async fn write_external_state(&self, request: Request) -> Result, Status> { + async fn write_external_state( + &self, + request: Request, + ) -> Result, Status> { let view_payload = request.into_inner().view_payload.expect("Error"); let request_id = view_payload.clone().request_id.to_string(); match view_payload.state { @@ -198,7 +228,7 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(reply)); } - } + }, None => {} } let reply_error = Ack { @@ -208,6 +238,84 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(reply_error)); } + + async fn perform_lock( + &self, + request: Request, + ) -> Result, Status> { + println!("Got a request from {:?}", request.remote_addr()); + let perform_lock_request = request.into_inner().clone(); + println!("The asset has been locked"); + let request_id = perform_lock_request.session_id.to_string(); + + let relays_table = self + .config_lock + .read() + .await + .get_table("relays") + .expect("No relays table in config file"); + let requesting_relay = get_relay_from_perform_lock(perform_lock_request); + let relay_uri = relays_table + .get(&requesting_relay.to_string()) + .expect("Requesting relay not found in config file relays table"); + let uri = relay_uri + .clone() + .try_into::() + .expect("Syntax for relays table in config file not correct"); + + let relay_port = uri.port.to_string(); + let relay_hostname = uri.hostname.to_string(); + let use_tls = uri.tls; + let tlsca_cert_path = uri.tlsca_cert_path.to_string(); + let client_addr = format!("http://{}:{}", relay_hostname, relay_port); + + if use_tls { + let pem = tokio::fs::read(tlsca_cert_path).await.unwrap(); + let ca = Certificate::from_pem(pem); + + let tls = ClientTlsConfig::new() + .ca_certificate(ca) + .domain_name(relay_hostname); + + let channel = Channel::from_shared(client_addr.to_string()) + .unwrap() + .tls_config(tls) + .expect(&format!( + "Error in TLS configuration for client: {}", + client_addr.to_string() + )) + .connect() + .await + .unwrap(); + + let client = SatpClient::new(channel); + send_driver_mock_send_asset_status_helper(client, request_id.to_string()); + } else { + let client_result = SatpClient::connect(client_addr).await; + match client_result { + Ok(client) => { + // Sends Mocked payload back. + send_driver_mock_send_asset_status_helper(client, request_id.to_string()); + } + Err(e) => { + // TODO: Add better error handling (Attempt a few times?) + panic!("Failed to connect to client. Error: {}", e.to_string()); + } + } + } + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id, + message: "".to_string(), + }; + return Ok(Response::new(reply)); + } +} + +pub fn get_relay_from_perform_lock(perform_lock_request: PerformLockRequest) -> String { + // TODO + return "Dummy_Relay".to_string(); } fn send_driver_mock_state_helper(client: DataTransferClient, request_id: String) { @@ -220,7 +328,7 @@ fn send_driver_mock_state_helper(client: DataTransferClient, request_id timestamp: "I am time".to_string(), proof_type: "I am proof".to_string(), serialization_format: "Proto".to_string(), - protocol: meta::Protocol::Fabric as i32 + protocol: meta::Protocol::Fabric as i32, }), data: "This is a mocked payload".as_bytes().to_vec(), })), @@ -231,7 +339,10 @@ fn send_driver_mock_state_helper(client: DataTransferClient, request_id println!("Ack from remote relay={:?}", response); }); } -fn send_driver_mock_subscription_state_helper(client: EventSubscribeClient, request_id: String) { +fn send_driver_mock_subscription_state_helper( + client: EventSubscribeClient, + request_id: String, +) { tokio::spawn(async move { let my_time = time::Duration::from_millis(3000); sleep(my_time); @@ -246,6 +357,31 @@ fn send_driver_mock_subscription_state_helper(client: EventSubscribeClient, request_id: String) { + tokio::spawn(async move { + let my_time = time::Duration::from_millis(3000); + sleep(my_time); + + let send_asset_status_request = SendAssetStatusRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + hash_prev_message: "hash_prev_message1".to_string(), + server_transfer_number: "server_transfer_number1".to_string(), + server_signature: "server_signature1".to_string(), + status: "status1".to_string(), + }; + println!("Sending send asset status request to remote gateway ..."); + let response = client + .clone() + .send_asset_status(send_asset_status_request) + .await; + println!("Ack from remote relay={:?}", response); + }); +} + #[tokio::main] async fn main() -> Result<(), Box> { // NOTE: This will need cleaning up @@ -282,7 +418,7 @@ async fn main() -> Result<(), Box> { .to_socket_addrs()? .next() .expect("Port number is potentially invalid. Unable to create SocketAddr"); - + let driver = DriverCommunicationService { config_lock: RwLock::new(settings.clone()), }; @@ -297,11 +433,11 @@ async fn main() -> Result<(), Box> { .tls_config(ServerTlsConfig::new().identity(identity))? .add_service(DriverCommunicationServer::new(driver)); server.serve(addr).await?; - } else { println!("DriverServer listening on {}", addr); // Spins up two gRPC services in a tonic server. One for relay to relay and one for network to relay communication. - let server = Server::builder().add_service(DriverCommunicationServer::new(driver)); + let server = + Server::builder().add_service(DriverCommunicationServer::new(driver)); server.serve(addr).await?; } } diff --git a/weaver/core/relay/src/services/helpers.rs b/weaver/core/relay/src/services/helpers.rs index 606edcad65..c3df19b069 100644 --- a/weaver/core/relay/src/services/helpers.rs +++ b/weaver/core/relay/src/services/helpers.rs @@ -2,20 +2,21 @@ // // SPDX-License-Identifier: Apache-2.0 +use colored::Colorize; use weaverpb::common::ack::{ack}; +use weaverpb::common::events::{event_subscription_state, EventSubscriptionState}; +use weaverpb::common::events::{EventPublication, EventState, EventStates, EventSubscription}; use weaverpb::common::query::Query; use weaverpb::common::state::{request_state, RequestState}; -use weaverpb::common::events::{event_subscription_state, EventSubscriptionState}; -use weaverpb::common::events::{EventSubscription, EventStates, EventState, EventPublication}; use weaverpb::driver::driver::driver_communication_client::DriverCommunicationClient; use crate::db::Database; -use crate::services::types::{Driver, Network}; use crate::error::Error; +use crate::services::types::{Driver, Network}; use config; -use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use std::fs; +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; // Locally scoped function to update request status in db. This function is // called for the first time after an Ack is received from the remote relay. @@ -30,11 +31,20 @@ pub fn update_event_subscription_status( db_open_retry_backoff_msec: u32, message: String, ) { - let driver_error_constants = fs::read_to_string("./driver/driver-error-constants.json").expect("Unable to read file: ./driver/driver-error-constants.json"); + let driver_error_constants = fs::read_to_string("./driver/driver-error-constants.json") + .expect("Unable to read file: ./driver/driver-error-constants.json"); let driver_error_constants_json: serde_json::Value = serde_json::from_str(&driver_error_constants).expect("JSON was not well-formatted"); - let driver_sub_exists_error = driver_error_constants_json.get("SUB_EXISTS").unwrap().as_str().unwrap(); - let driver_sub_exists_error_without_args = *(driver_sub_exists_error.split("{0}").collect::>().first().unwrap()); + let driver_sub_exists_error = driver_error_constants_json + .get("SUB_EXISTS") + .unwrap() + .as_str() + .unwrap(); + let driver_sub_exists_error_without_args = *(driver_sub_exists_error + .split("{0}") + .collect::>() + .first() + .unwrap()); let db = Database { db_path: curr_db_path, @@ -53,42 +63,52 @@ pub fn update_event_subscription_status( target = EventSubscriptionState { status: event_subscription_state::Status::UnsubscribePending as i32, request_id: curr_request_id.clone(), - publishing_request_id: fetched_event_sub_state.publishing_request_id.to_string(), + publishing_request_id: fetched_event_sub_state + .publishing_request_id + .to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher, - event_publication_specs: fetched_event_sub_state.event_publication_specs + event_publication_specs: fetched_event_sub_state + .event_publication_specs, }; - }, + } event_subscription_state::Status::UnsubscribePending => { target = EventSubscriptionState { status: event_subscription_state::Status::Unsubscribed as i32, request_id: curr_request_id.clone(), - publishing_request_id: fetched_event_sub_state.publishing_request_id.to_string(), + publishing_request_id: fetched_event_sub_state + .publishing_request_id + .to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher, - event_publication_specs: fetched_event_sub_state.event_publication_specs + event_publication_specs: fetched_event_sub_state + .event_publication_specs, }; - }, - event_subscription_state::Status::SubscribePendingAck => { + } + event_subscription_state::Status::SubscribePendingAck => { target = EventSubscriptionState { status: event_subscription_state::Status::SubscribePending as i32, request_id: curr_request_id.clone(), publishing_request_id: "".to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, - event_subscription_state::Status::SubscribePending => { + } + event_subscription_state::Status::SubscribePending => { target = EventSubscriptionState { status: event_subscription_state::Status::Subscribed as i32, request_id: curr_request_id.clone(), publishing_request_id: curr_request_id.clone(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, + } _ => { target = EventSubscriptionState { status: event_subscription_state::Status::Error as i32, @@ -96,9 +116,11 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: "Status is not supported or is invalid".to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, + } }, None => { target = EventSubscriptionState { @@ -107,41 +129,61 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: "No event subscription status set in database".to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; - }, + } } } else { match message.find(driver_sub_exists_error_without_args) { Some(_index) => { - let old_request_id = *(message.split(driver_sub_exists_error_without_args).collect::>().last().unwrap()); + let old_request_id = *(message + .split(driver_sub_exists_error_without_args) + .collect::>() + .last() + .unwrap()); println!("Adding event publication spec to existing EventSubscriptionState. Extracted request id from message: {}", old_request_id.to_string()); - let old_event_sub_key = get_event_subscription_key(old_request_id.to_string()); - let mut existing_event_sub_state = db.get::(old_event_sub_key.to_string()) - .expect(&format!("No EventSubscriptionState found in DB for request_id provided {}", old_request_id.to_string())); - - let new_event_pub_spec = fetched_event_sub_state.event_publication_specs.first().unwrap(); + let old_event_sub_key = + get_event_subscription_key(old_request_id.to_string()); + let mut existing_event_sub_state = db + .get::(old_event_sub_key.to_string()) + .expect(&format!( + "No EventSubscriptionState found in DB for request_id provided {}", + old_request_id.to_string() + )); + + let new_event_pub_spec = fetched_event_sub_state + .event_publication_specs + .first() + .unwrap(); let mut unique_pub_spec_flag = true; - for event_pub_spec in existing_event_sub_state.event_publication_specs.iter() { + for event_pub_spec in + existing_event_sub_state.event_publication_specs.iter() + { if *new_event_pub_spec == *event_pub_spec { unique_pub_spec_flag = false; break; } } if unique_pub_spec_flag { - existing_event_sub_state.event_publication_specs.push((*new_event_pub_spec).clone()); + existing_event_sub_state + .event_publication_specs + .push((*new_event_pub_spec).clone()); let updated_event_sub_state = EventSubscriptionState { status: event_subscription_state::Status::Subscribed as i32, request_id: old_request_id.to_string(), publishing_request_id: old_request_id.to_string(), message: existing_event_sub_state.message.to_string(), event_matcher: existing_event_sub_state.event_matcher.clone(), - event_publication_specs: existing_event_sub_state.event_publication_specs.clone(), + event_publication_specs: existing_event_sub_state + .event_publication_specs + .clone(), }; db.set(&old_event_sub_key.to_string(), &updated_event_sub_state) .expect("Failed to insert into DB"); - + target = EventSubscriptionState { status: event_subscription_state::Status::DuplicateQuerySubscribed as i32, request_id: curr_request_id.clone(), @@ -157,10 +199,12 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), } }; - }, + } None => { target = EventSubscriptionState { status: event_subscription_state::Status::Error as i32, @@ -168,28 +212,31 @@ pub fn update_event_subscription_status( publishing_request_id: "".to_string(), message: message.to_string(), event_matcher: fetched_event_sub_state.event_matcher.clone(), - event_publication_specs: fetched_event_sub_state.event_publication_specs.clone(), + event_publication_specs: fetched_event_sub_state + .event_publication_specs + .clone(), }; } } } - + // Panic if this fails, atm the panic is just logged by the tokio runtime db.set(&event_sub_key.to_string(), &target) .expect("Failed to insert into DB"); println!("Successfully written EventSubscriptionState to database"); - println!("{:?}\n", db.get::(event_sub_key.to_string()).unwrap()) - }, + println!( + "{:?}\n", + db.get::(event_sub_key.to_string()) + .unwrap() + ) + } Err(e) => { println!("EventSubscription Request not found. Error: {:?}", e); - }, + } } } -pub fn get_driver( - network_id: String, - conf: config::Config, -) -> Result { +pub fn get_driver(network_id: String, conf: config::Config) -> Result { // get the driver type from the networks map let networks_table = conf .get_table("networks") @@ -239,7 +286,8 @@ pub async fn get_driver_client( .ca_certificate(ca) .domain_name(hostname); - let channel = Channel::from_shared(driver_address).unwrap() + let channel = Channel::from_shared(driver_address) + .unwrap() .tls_config(tls)? .connect() .await @@ -249,10 +297,9 @@ pub async fn get_driver_client( } else { client = DriverCommunicationClient::connect(driver_address).await?; } - return Ok(client) + return Ok(client); } - pub async fn driver_sign_subscription_helper( event_subscription: EventSubscription, request_id: String, @@ -263,7 +310,10 @@ pub async fn driver_sign_subscription_helper( match result { Ok(driver_info) => { let client = get_driver_client(driver_info).await?; - println!("Sending Sign EventSubscription Request to driver: {:?}", event_subscription.clone()); + println!( + "Sending Sign EventSubscription Request to driver: {:?}", + event_subscription.clone() + ); let signed_query = client .clone() .request_signed_event_subscription_query(event_subscription) @@ -271,10 +321,13 @@ pub async fn driver_sign_subscription_helper( .into_inner(); if signed_query.clone().request_id.to_string() == request_id.to_string() { println!("Signed Query Response from driver={:?}\n", signed_query); - return Ok(signed_query) + return Ok(signed_query); } - Err(Error::Simple(format!("Error while requesting signature from driver: {:?}", signed_query))) - }, + Err(Error::Simple(format!( + "Error while requesting signature from driver: {:?}", + signed_query + ))) + } Err(e) => Err(e), } } @@ -311,8 +364,7 @@ pub fn update_event_state( message: message.to_string(), }; updated_event_states.push(new_event_state); - } - else { + } else { updated_event_states.push(fetched_event_state); } } @@ -320,17 +372,18 @@ pub fn update_event_state( db.set(&event_publish_key.to_string(), &updated_event_states) .expect("Failed to insert into DB"); println!("Successfully updated EventStates in database"); - }, + } Err(e) => { println!("EventStates not found. Error: {:?}", e); - }, + } } } pub fn try_mark_request_state_deleted(state: RequestState, request_id: String, db: Database) { let state_status = request_state::Status::from_i32(state.clone().status).expect("No Status"); - if state_status == request_state::Status::Error || - state_status == request_state::Status::Completed { + if state_status == request_state::Status::Error + || state_status == request_state::Status::Completed + { let deleted_request_state = RequestState { status: request_state::Status::Deleted as i32, request_id: request_id.to_string(), @@ -341,7 +394,12 @@ pub fn try_mark_request_state_deleted(state: RequestState, request_id: String, d } } -pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: String, event_publish_key: String, db: Database) { +pub fn mark_event_states_deleted( + fetched_event_states: EventStates, + request_id: String, + event_publish_key: String, + db: Database, +) { let mut updated_event_states: Vec = Vec::new(); for fetched_event_state in fetched_event_states.states { let deleted_request_state = RequestState { @@ -356,7 +414,7 @@ pub fn mark_event_states_deleted(fetched_event_states: EventStates, request_id: }; updated_event_states.push(deleted_event_state); } - + db.set(&event_publish_key.to_string(), &updated_event_states) .expect("EventState Delete: Failed to insert into DB"); } @@ -381,11 +439,15 @@ pub fn delete_event_pub_spec( db_open_retry_backoff_msec: db_open_retry_backoff_msec, }; let mut event_sub_key = get_event_subscription_key(request_id.to_string()); - let mut event_sub_state = db.get::(event_sub_key.to_string()) - .expect(&format!("No EventSubscriptionState found in DB for request_id provided {}", request_id.to_string())); - + let mut event_sub_state = db + .get::(event_sub_key.to_string()) + .expect(&format!( + "No EventSubscriptionState found in DB for request_id provided {}", + request_id.to_string() + )); + let mut del_event_pub_spec = event_pub_spec; - + if event_sub_state.status == event_subscription_state::Status::DuplicateQuerySubscribed as i32 { let updated_state = EventSubscriptionState { status: event_subscription_state::Status::Unsubscribed as i32, @@ -393,18 +455,30 @@ pub fn delete_event_pub_spec( publishing_request_id: event_sub_state.publishing_request_id.to_string(), message: "Unsubscription successful".to_string(), event_matcher: event_sub_state.event_matcher, - event_publication_specs: event_sub_state.event_publication_specs + event_publication_specs: event_sub_state.event_publication_specs, }; db.set(&event_sub_key.to_string(), &updated_state) .expect("Failed to insert into DB"); - del_event_pub_spec = updated_state.clone().event_publication_specs.first().unwrap().clone(); - println!("Removed EventSubscriptionState from database: {:?}", updated_state); + del_event_pub_spec = updated_state + .clone() + .event_publication_specs + .first() + .unwrap() + .clone(); + println!( + "Removed EventSubscriptionState from database: {:?}", + updated_state + ); event_sub_key = get_event_subscription_key(updated_state.publishing_request_id.to_string()); - event_sub_state = db.get::(event_sub_key.to_string()) - .expect(&format!("No EventSubscriptionState found in DB for request_id provided {}", updated_state.publishing_request_id.to_string())); + event_sub_state = db + .get::(event_sub_key.to_string()) + .expect(&format!( + "No EventSubscriptionState found in DB for request_id provided {}", + updated_state.publishing_request_id.to_string() + )); } - + let mut flag = true; for (i, curr_event_pub_spec) in event_sub_state.event_publication_specs.iter().enumerate() { if *curr_event_pub_spec == del_event_pub_spec { @@ -422,13 +496,32 @@ pub fn delete_event_pub_spec( db.set(&event_sub_key.to_string(), &event_sub_state) .expect("Failed to insert into DB"); println!("Successfully deleted Event Publication from existing EventSubscriptionState from DB"); - + return 0; } pub fn get_event_subscription_key(request_id: String) -> String { return format!("event_sub_{}", request_id); } + pub fn get_event_publication_key(request_id: String) -> String { return format!("event_pub_{}", request_id); -} \ No newline at end of file +} + +pub fn println_stage_heading(stage_id: String) { + println!( + "{} {} {}", + "\n --------- Stage".yellow().bold(), + stage_id.yellow().bold(), + "started --------- \n".yellow().bold() + ); +} + +pub fn println_step_heading(step_id: String) { + println!( + "{} {} {}", + "\n --------- Step".bright_cyan().bold(), + step_id.bright_cyan().bold(), + " --------- \n".bright_cyan().bold() + ); +} diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 2ae2076a8b..1d253ce9c5 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -597,7 +597,7 @@ impl Network for NetworkService { let (relay_host, relay_port) = get_relay_from_transfer_proposal_claims( transfer_proposal_claims_request.clone(), ); - let (use_tls, relay_tlsca_cert_path) = + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); // TODO: verify that host and port are valid @@ -607,7 +607,7 @@ impl Network for NetworkService { relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); // Send Ack back to network while request is happening in a thread @@ -809,12 +809,12 @@ fn spawn_send_request( // Iterate through the relay entries in the configuration to find a match let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; - let mut relay_tlsca_cert_path = "".to_string(); + let mut tlsca_cert_path = "".to_string(); for (_relay_name, relay_spec) in relays_table { let relay_uri = relay_spec.clone().try_into::().unwrap(); if relay_host == relay_uri.hostname && relay_port == relay_uri.port { relay_tls = relay_uri.tls; - relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + tlsca_cert_path = relay_uri.tlsca_cert_path; } } @@ -825,7 +825,7 @@ fn spawn_send_request( network_query, request_id.clone(), relay_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), ) .await; println!("Received Ack from remote relay: {:?}\n", result); @@ -948,12 +948,12 @@ fn spawn_send_event_subscription_request( // Iterate through the relay entries in the configuration to find a match let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; - let mut relay_tlsca_cert_path = "".to_string(); + let mut tlsca_cert_path = "".to_string(); for (_relay_name, relay_spec) in relays_table { let relay_uri = relay_spec.clone().try_into::().unwrap(); if relay_host == relay_uri.hostname && relay_port == relay_uri.port { relay_tls = relay_uri.tls; - relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + tlsca_cert_path = relay_uri.tlsca_cert_path; } } @@ -962,7 +962,7 @@ fn spawn_send_event_subscription_request( relay_port, event_subscription, relay_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), ) .await; println!("Received Ack from remote relay: {:?}\n", result); diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 9405543f35..61c13bf146 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -6,21 +6,28 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use tonic::Response; use weaverpb::common::ack::{ack, Ack}; use weaverpb::common::state::{request_state, RequestState}; +use weaverpb::driver::driver::{ + AssignAssetRequest, CreateAssetRequest, ExtinguishRequest, PerformLockRequest, +}; use weaverpb::networks::networks::NetworkAssetTransfer; use weaverpb::relay::satp::satp_client::SatpClient; use weaverpb::relay::satp::{ - AckCommenceRequest, LockAssertionRequest, TransferCommenceRequest, - TransferProposalClaimsRequest, TransferProposalReceiptRequest, + AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, + CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, SendAssetStatusRequest, + TransferCommenceRequest, TransferCompletedRequest, TransferProposalClaimsRequest, + TransferProposalReceiptRequest, }; use crate::db::Database; use crate::error::{self, Error}; use crate::relay_proto::LocationSegment; +use crate::services::helpers::get_driver_client; use super::constants::{ SATP_DB_PATH, SATP_REMOTE_REQUESTS_DB_PATH, SATP_REMOTE_REQUESTS_STATES_DB_PATH, SATP_REQUESTS_DB_PATH, SATP_REQUESTS_STATES_DB_PATH, }; +use super::types::Driver; // Sends a request to the receiving gateway pub fn spawn_send_transfer_proposal_claims_request( @@ -28,7 +35,7 @@ pub fn spawn_send_transfer_proposal_claims_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { println!( @@ -47,7 +54,7 @@ pub fn spawn_send_transfer_proposal_claims_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), transfer_proposal_claims_request.clone(), ) .await; @@ -64,7 +71,7 @@ pub fn spawn_send_transfer_commence_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { println!( @@ -82,7 +89,7 @@ pub fn spawn_send_transfer_commence_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), transfer_commence_request.clone(), ) .await; @@ -98,7 +105,7 @@ pub fn spawn_send_transfer_proposal_receipt_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { @@ -113,7 +120,7 @@ pub fn spawn_send_transfer_proposal_receipt_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), transfer_proposal_receipt_request.clone(), ) .await; @@ -129,7 +136,7 @@ pub fn spawn_send_ack_commence_request( relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { @@ -142,7 +149,7 @@ pub fn spawn_send_ack_commence_request( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), ack_commence_request.clone(), ) .await; @@ -154,28 +161,81 @@ pub fn spawn_send_ack_commence_request( } pub fn spawn_send_perform_lock_request( + driver_info: Driver, + perform_lock_request: PerformLockRequest, +) { + tokio::spawn(async move { + let request_id = perform_lock_request.session_id.to_string(); + println!( + "Locking the asset of the lock assertion request id: {:?}", + request_id + ); + // TODO: pass the required info to lock the relevant asset + // Call the driver to lock the asset + let result = call_perform_lock(driver_info, perform_lock_request).await; + match result { + Ok(_) => { + println!("Perform lock request sent to driver\n") + } + Err(e) => { + println!("Error sending perform lock request to driver: {:?}\n", e); + // TODO: what to do in this case? + } + } + }); +} + +pub fn spawn_send_lock_assertion_broadcast_request( lock_assertion_request: LockAssertionRequest, relay_host: String, relay_port: String, use_tls: bool, - relay_tlsca_cert_path: String, + tlsca_cert_path: String, conf: Config, ) { tokio::spawn(async move { - println!( - "Locking the asset of the lock assertion request {:?}", - lock_assertion_request - ); + let request_id = lock_assertion_request.session_id.to_string(); + println!("Broadcasting the lock assertion request {:?}", request_id); // TODO - // Call the driver to check the asset status + // Broadcast the message to the network // Subscribe to the status event - // Once the asset is locked, call the lock_assertion endpoint + // Once the message is broadcast, call the call_lock_assertion_receipt endpoint // log the results + + let lock_assertion_receipt_request = + create_lock_assertion_receipt_request(lock_assertion_request.clone()); + let result = call_lock_assertion_receipt( + relay_host, + relay_port, + use_tls, + tlsca_cert_path.to_string(), + lock_assertion_receipt_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = lock_assertion_receipt_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_lock_assertion_request( + lock_assertion_request: LockAssertionRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = lock_assertion_request.session_id.to_string(); + println!("Sending the lock assertion request {:?}", request_id); let result = call_lock_assertion( relay_host, relay_port, use_tls, - relay_tlsca_cert_path.to_string(), + tlsca_cert_path.to_string(), lock_assertion_request.clone(), ) .await; @@ -187,6 +247,329 @@ pub fn spawn_send_perform_lock_request( }); } +// Sends a request to the receiving gateway +pub fn spawn_send_commit_prepare_request( + commit_prepare_request: CommitPrepareRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + println!( + "Sending commit prepare request to receiver gateway: {:?}:{:?}", + relay_host, relay_port + ); + // Spawning new thread to make the call_commit_prepare to receiver gateway + tokio::spawn(async move { + let request_id = commit_prepare_request.session_id.to_string(); + let result = call_commit_prepare( + relay_host, + relay_port, + use_tls, + tlsca_cert_path.to_string(), + commit_prepare_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_create_asset_request( + driver_info: Driver, + create_asset_request: CreateAssetRequest, +) { + tokio::spawn(async move { + let request_id = create_asset_request.session_id.to_string(); + println!( + "Creating the asset corresponding to the create asset request {:?}", + request_id + ); + + // TODO: pass the required info to lock the relevant asset + // Call the driver to lock the asset + let result = call_create_asset(driver_info, create_asset_request).await; + match result { + Ok(_) => { + println!("Create asset request sent to driver\n") + } + Err(e) => { + println!("Error sending create asset request to driver: {:?}\n", e); + // TODO: what to do in this case? + } + } + }); +} + +pub fn spawn_send_commit_ready_request( + commit_ready_request: CommitReadyRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = commit_ready_request.session_id.to_string(); + let result = call_commit_ready( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + commit_ready_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = commit_ready_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_assign_asset_request( + driver_info: Driver, + assign_asset_request: AssignAssetRequest, +) { + tokio::spawn(async move { + let request_id = assign_asset_request.session_id.to_string(); + println!( + "Assigning the asset corresponding to the assign asset request {:?}", + request_id + ); + + // TODO: pass the required info to assign the relevant asset + // Call the driver to assign the asset + let result = call_assign_asset(driver_info, assign_asset_request).await; + match result { + Ok(_) => { + println!("Assign asset request sent to driver\n") + } + Err(e) => { + println!("Error sending assign asset request to driver: {:?}\n", e); + // TODO: what to do in this case? + } + } + }); +} + +pub fn spawn_send_ack_final_receipt_request( + ack_final_receipt_request: AckFinalReceiptRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = ack_final_receipt_request.session_id.to_string(); + let result = call_ack_final_receipt( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + ack_final_receipt_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = ack_final_receipt_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_ack_final_receipt_broadcast_request( + ack_final_receipt_request: AckFinalReceiptRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = ack_final_receipt_request.session_id.to_string(); + println!( + "Acknowledge final receipt broadcast of the ack final receipt request {:?}", + request_id + ); + // TODO + // Ack final receipt broadcast + // Once the broadcast is done, call the call_transfer_completed endpoint + // log the results + + let transfer_completed_request = + create_transfer_completed_request(ack_final_receipt_request); + let result = call_transfer_completed( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + transfer_completed_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = transfer_completed_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +pub fn spawn_send_extinguish_request(driver_info: Driver, extinguish_request: ExtinguishRequest) { + tokio::spawn(async move { + let request_id = extinguish_request.session_id.to_string(); + println!( + "Extinguishing the asset corresponding to the extinguish request {:?}", + request_id + ); + + // TODO: pass the required info to lock the relevant asset + // Call the driver to lock the asset + let result = call_extinguish(driver_info, extinguish_request).await; + match result { + Ok(_) => { + println!("Extinguishing asset request sent to driver\n") + } + Err(e) => { + println!( + "Error sending extinguishing asset request to driver: {:?}\n", + e + ); + // TODO: what to do in this case? + } + } + }); +} + +pub fn spawn_send_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + conf: Config, +) { + tokio::spawn(async move { + let request_id = commit_final_assertion_request.session_id.to_string(); + println!( + "Extinguishing the asset corresponding to the commit final assertion request {:?}", + request_id + ); + let result = call_commit_final_assertion_receipt( + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + commit_final_assertion_request.clone(), + ) + .await; + + println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = commit_final_assertion_request.session_id.to_string(); + log_request_result_in_local_satp_db(&request_id, result, conf); + }); +} + +async fn call_perform_lock( + driver_info: Driver, + perform_lock_request: PerformLockRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to lock the asset"); + let ack = client + .clone() + .perform_lock(perform_lock_request) + .await? + .into_inner(); + println!("Response ACK from driver to perform lock {:?}\n", ack); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + +async fn call_create_asset( + driver_info: Driver, + create_asset_request: CreateAssetRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to create the asset"); + let ack = client + .clone() + .create_asset(create_asset_request) + .await? + .into_inner(); + println!("Response ACK from driver to create the asset {:?}\n", ack); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + +async fn call_extinguish( + driver_info: Driver, + extinguish_request: ExtinguishRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to extinguish the asset"); + let ack = client + .clone() + .extinguish(extinguish_request) + .await? + .into_inner(); + println!( + "Response ACK from driver to extinguish the asset {:?}\n", + ack + ); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + +async fn call_assign_asset( + driver_info: Driver, + assign_asset_request: AssignAssetRequest, +) -> Result<(), Error> { + let client = get_driver_client(driver_info).await?; + println!("Sending request to driver to assign the asset"); + let ack = client + .clone() + .assign_asset(assign_asset_request) + .await? + .into_inner(); + println!("Response ACK from driver to assign the asset {:?}\n", ack); + let status = ack::Status::from_i32(ack.status) + .ok_or(Error::Simple("Status from Driver error".to_string()))?; + match status { + ack::Status::Ok => { + // Do nothing + return Ok(()); + } + ack::Status::Error => Err(Error::Simple(format!("Error from driver: {}", ack.message))), + } +} + // Call the transfer_commence endpoint on the receiver gateway pub async fn call_transfer_commence( relay_host: String, @@ -287,6 +670,126 @@ pub async fn call_lock_assertion( Ok(response) } +// Call the ack_commence endpoint on the sending gateway +pub async fn call_lock_assertion_receipt( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the lock assertion receipt request: {:?}", + lock_assertion_receipt_request.clone() + ); + let response = satp_client + .lock_assertion_receipt(lock_assertion_receipt_request.clone()) + .await?; + Ok(response) +} + +// Call the call_commit_prepare endpoint on the sending gateway +pub async fn call_commit_prepare( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + commit_prepare_request: CommitPrepareRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the commit prepare request: {:?}", + commit_prepare_request.clone() + ); + let response = satp_client + .commit_prepare(commit_prepare_request.clone()) + .await?; + Ok(response) +} + +// Call the call_commit_ready endpoint on the sending gateway +pub async fn call_commit_ready( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + commit_ready_request: CommitReadyRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the commit ready request: {:?}", + commit_ready_request.clone() + ); + let response = satp_client + .commit_ready(commit_ready_request.clone()) + .await?; + Ok(response) +} + +// Call the call_ack_final_receipt endpoint on the sending gateway +pub async fn call_ack_final_receipt( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + ack_final_receipt_request: AckFinalReceiptRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the ack final receipt request: {:?}", + ack_final_receipt_request.clone() + ); + let response = satp_client + .ack_final_receipt(ack_final_receipt_request.clone()) + .await?; + Ok(response) +} + +// Call the call_transfer_completed endpoint on the sending gateway +pub async fn call_transfer_completed( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + transfer_completed_request: TransferCompletedRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the transfer completed request: {:?}", + transfer_completed_request.clone() + ); + let response = satp_client + .transfer_completed(transfer_completed_request.clone()) + .await?; + Ok(response) +} + +// Call the call_commit_final_assertion_receipt endpoint on the sending gateway +pub async fn call_commit_final_assertion_receipt( + relay_host: String, + relay_port: String, + use_tls: bool, + tlsca_cert_path: String, + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> Result, Box> { + let mut satp_client: SatpClient = + create_satp_client(relay_host, relay_port, use_tls, tlsca_cert_path).await?; + println!( + "Sending the commit final assertion request: {:?}", + commit_final_assertion_request.clone() + ); + let response = satp_client + .commit_final_assertion(commit_final_assertion_request.clone()) + .await?; + Ok(response) +} + pub fn log_request_result_in_local_satp_db( request_id: &String, result: Result, Box>, @@ -427,7 +930,7 @@ pub fn create_ack_commence_request( } pub fn create_lock_assertion_request( - ack_commence_request: AckCommenceRequest, + send_asset_status_request: SendAssetStatusRequest, ) -> LockAssertionRequest { // TODO: remove hard coded values let lock_assertion_request = LockAssertionRequest { @@ -446,6 +949,158 @@ pub fn create_lock_assertion_request( return lock_assertion_request; } +pub fn create_lock_assertion_receipt_request( + lock_assertion_request: LockAssertionRequest, +) -> LockAssertionReceiptRequest { + // TODO: remove hard coded values + let lock_assertion_receipt_request = LockAssertionReceiptRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + client_identity_pubkey: "client_identity_pubkey1".to_string(), + server_identity_pubkey: "server_identity_pubkey1".to_string(), + hash_prev_message: "hash_prev_message1".to_string(), + server_transfer_number: "server_transfer_number1".to_string(), + server_signature: "server_signature1".to_string(), + }; + return lock_assertion_receipt_request; +} + +pub fn create_commit_prepare_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> CommitPrepareRequest { + // TODO: remove hard coded values + let commit_prepare_request = CommitPrepareRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_prepare_request; +} + +pub fn create_commit_ready_request( + send_asset_status_request: SendAssetStatusRequest, +) -> CommitReadyRequest { + // TODO: remove hard coded values + let commit_ready_request = CommitReadyRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_ready_request; +} + +pub fn create_commit_final_assertion_request( + send_asset_status_request: SendAssetStatusRequest, +) -> CommitFinalAssertionRequest { + // TODO: remove hard coded values + let commit_final_assertion_request = CommitFinalAssertionRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_final_assertion_request; +} + +pub fn create_ack_final_receipt_request( + send_asset_status_request: SendAssetStatusRequest, +) -> AckFinalReceiptRequest { + // TODO: remove hard coded values + let ack_final_receipt_request = AckFinalReceiptRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return ack_final_receipt_request; +} + +pub fn create_transfer_completed_request( + ack_final_receipt_request: AckFinalReceiptRequest, +) -> TransferCompletedRequest { + // TODO: remove hard coded values + let transfer_completed_request = TransferCompletedRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return transfer_completed_request; +} + +pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> PerformLockRequest { + // TODO: remove hard coded values + let perform_lock_request = PerformLockRequest { + session_id: "session_id1".to_string(), + }; + return perform_lock_request; +} + +pub fn create_create_asset_request( + commit_prepare_request: CommitPrepareRequest, +) -> CreateAssetRequest { + // TODO: remove hard coded values + let create_asset_request = CreateAssetRequest { + session_id: "session_id1".to_string(), + }; + return create_asset_request; +} + +pub fn create_extinguish_request(commit_ready_request: CommitReadyRequest) -> ExtinguishRequest { + // TODO: remove hard coded values + let extinguish_request = ExtinguishRequest { + session_id: "session_id1".to_string(), + }; + return extinguish_request; +} + +pub fn create_assign_asset_request( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> AssignAssetRequest { + // TODO: remove hard coded values + let assign_asset_request = AssignAssetRequest { + session_id: "session_id1".to_string(), + }; + return assign_asset_request; +} + +pub fn generate_commit_final_assertion_request( + commit_ready_request: CommitReadyRequest, +) -> CommitFinalAssertionRequest { + // TODO Get the corresponding send_asset_status_request from db + // TODO: remove hard coded values + let commit_final_assertion_request = CommitFinalAssertionRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_final_assertion_request; +} + +pub fn generate_commit_ready_request( + commit_prepare_request: CommitPrepareRequest, +) -> CommitReadyRequest { + // TODO Get the corresponding send_asset_status_request from db + // TODO: remove hard coded values + let commit_ready_request = CommitReadyRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return commit_ready_request; +} + +pub fn generate_ack_final_receipt_request( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> AckFinalReceiptRequest { + // TODO Get the corresponding send_asset_status_request from db + // TODO: remove hard coded values + let ack_final_receipt_request = AckFinalReceiptRequest { + message_type: "message_type1".to_string(), + session_id: "session_id1".to_string(), + transfer_context_id: "transfer_context_id1".to_string(), + }; + return ack_final_receipt_request; +} + pub fn get_satp_requests_local_db(conf: Config) -> Database { let db = Database { db_path: format!( @@ -554,7 +1209,6 @@ pub fn update_request_state_in_local_satp_db( println!("{:?}\n", db.get::(request_id).unwrap()) } -// Get the requesting relay host and port pub fn get_relay_from_transfer_proposal_claims( transfer_proposal_claims_request: TransferProposalClaimsRequest, ) -> (String, String) { @@ -562,7 +1216,6 @@ pub fn get_relay_from_transfer_proposal_claims( return ("localhost".to_string(), "9085".to_string()); } -// Get the requesting relay host and port pub fn get_relay_from_transfer_proposal_receipt( transfer_proposal_receipt_request: TransferProposalReceiptRequest, ) -> (String, String) { @@ -570,7 +1223,6 @@ pub fn get_relay_from_transfer_proposal_receipt( return ("localhost".to_string(), "9085".to_string()); } -// Get the requesting relay host and port pub fn get_relay_from_transfer_commence( transfer_commence_request: TransferCommenceRequest, ) -> (String, String) { @@ -578,24 +1230,90 @@ pub fn get_relay_from_transfer_commence( return ("localhost".to_string(), "9085".to_string()); } -// Get the requesting relay host and port pub fn get_relay_from_ack_commence(ack_commence_request: AckCommenceRequest) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } +pub fn get_relay_from_lock_assertion( + lock_assertion_request: LockAssertionRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_lock_assertion_receipt( + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_commit_prepare( + commit_prepare_request: CommitPrepareRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_commit_ready(commit_ready_request: CommitReadyRequest) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_commit_final_assertion( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_ack_final_receipt( + ack_final_receipt_request: AckFinalReceiptRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_relay_from_send_asset_status( + send_asset_status_request: SendAssetStatusRequest, +) -> (String, String) { + // TODO + return ("localhost".to_string(), "9085".to_string()); +} + +pub fn get_driver_address_from_perform_lock(perform_lock_request: PerformLockRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + +pub fn get_driver_address_from_create_asset(create_asset_request: CreateAssetRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + +pub fn get_driver_address_from_extinguish(extinguish_request: ExtinguishRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + +pub fn get_driver_address_from_assign_asset(assign_asset_request: AssignAssetRequest) -> String { + // TODO + return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); +} + pub fn get_relay_params(relay_host: String, relay_port: String, conf: Config) -> (bool, String) { let relays_table = conf.get_table("relays").unwrap(); let mut relay_tls = false; - let mut relay_tlsca_cert_path = "".to_string(); + let mut tlsca_cert_path = "".to_string(); for (_relay_name, relay_spec) in relays_table { let relay_uri = relay_spec.clone().try_into::().unwrap(); if relay_host == relay_uri.hostname && relay_port == relay_uri.port { relay_tls = relay_uri.tls; - relay_tlsca_cert_path = relay_uri.tlsca_cert_path; + tlsca_cert_path = relay_uri.tlsca_cert_path; } } - (relay_tls, relay_tlsca_cert_path) + (relay_tls, tlsca_cert_path) } fn create_client_address(relay_host: String, relay_port: String) -> String { diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 8037f6127e..7ed1536339 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,25 +1,46 @@ // Internal generated modules use weaverpb::common::ack::{ack, Ack}; +use weaverpb::driver::driver::{ + AssignAssetRequest, CreateAssetRequest, ExtinguishRequest, PerformLockRequest, +}; use weaverpb::relay::satp::satp_server::Satp; use weaverpb::relay::satp::{ - AckCommenceRequest, LockAssertionReceiptRequest, LockAssertionRequest, TransferCommenceRequest, - TransferProposalClaimsRequest, TransferProposalReceiptRequest, + AckCommenceRequest, AckFinalReceiptRequest, CommitFinalAssertionRequest, CommitPrepareRequest, + CommitReadyRequest, LockAssertionReceiptRequest, LockAssertionRequest, SendAssetStatusRequest, + TransferCommenceRequest, TransferCompletedRequest, TransferProposalClaimsRequest, + TransferProposalReceiptRequest, }; // Internal modules use crate::error::Error; +use crate::relay_proto::parse_address; +use crate::services::helpers::{println_stage_heading, println_step_heading}; use crate::services::satp_helper::{ - create_ack_error_message, get_request_id_from_transfer_proposal_receipt, - log_request_in_local_satp_db, log_request_in_remote_satp_db, + create_ack_error_message, create_assign_asset_request, create_create_asset_request, + create_extinguish_request, create_perform_lock_request, + get_request_id_from_transfer_proposal_receipt, log_request_in_local_satp_db, + log_request_in_remote_satp_db, }; +use super::helpers::get_driver; // external modules use super::satp_helper::{ - create_ack_commence_request, create_lock_assertion_request, create_transfer_commence_request, - create_transfer_proposal_receipt_request, get_relay_from_ack_commence, - get_relay_from_transfer_commence, get_relay_from_transfer_proposal_claims, + create_ack_commence_request, create_ack_final_receipt_request, + create_commit_final_assertion_request, create_commit_prepare_request, + create_commit_ready_request, create_lock_assertion_request, create_transfer_commence_request, + create_transfer_completed_request, create_transfer_proposal_receipt_request, + get_driver_address_from_assign_asset, get_driver_address_from_create_asset, + get_driver_address_from_extinguish, get_driver_address_from_perform_lock, + get_relay_from_ack_commence, get_relay_from_ack_final_receipt, + get_relay_from_commit_final_assertion, get_relay_from_commit_prepare, + get_relay_from_commit_ready, get_relay_from_lock_assertion, get_relay_from_transfer_commence, get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, + spawn_send_ack_final_receipt_broadcast_request, spawn_send_ack_final_receipt_request, + spawn_send_assign_asset_request, spawn_send_commit_final_assertion_request, + spawn_send_commit_prepare_request, spawn_send_commit_ready_request, + spawn_send_create_asset_request, spawn_send_extinguish_request, + spawn_send_lock_assertion_broadcast_request, spawn_send_lock_assertion_request, spawn_send_perform_lock_request, spawn_send_transfer_commence_request, spawn_send_transfer_proposal_receipt_request, }; @@ -40,6 +61,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_stage_heading("1".to_string()); + println_step_heading("1.1".to_string()); println!( "Got a TransferProposalClaimsRequest from {:?} - {:?}", request.remote_addr(), @@ -93,6 +116,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("1.2".to_string()); println!( "Got an ack transfer proposal receipt request from {:?} - {:?}", request.remote_addr(), @@ -154,6 +178,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("1.3".to_string()); println!( "Got a TransferCommenceRequest from {:?} - {:?}", request.remote_addr(), @@ -199,6 +224,7 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + println_step_heading("1.4".to_string()); println!( "Got an ack commence request from {:?} - {:?}", request.remote_addr(), @@ -242,244 +268,860 @@ impl Satp for SatpService { } } - async fn lock_assertion( + async fn send_asset_status( &self, - request: Request, + request: Request, ) -> Result, Status> { println!( - "Got a lock assertion request from {:?} - {:?}", + "Got a send asset status request from {:?} - {:?}", request.remote_addr(), request ); - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: "xxxxxxxxx".to_string(), - message: format!("Error: Not implemented yet."), - })); - println!("Sending back Ack: {:?}\n", reply); - reply + + let send_asset_status_request = request.into_inner().clone(); + let request_id = send_asset_status_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &send_asset_status_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored SendAssetStatusRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing SendAssetStatusRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_send_asset_status_request(send_asset_status_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of send asset status request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Send asset status failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } } - async fn lock_assertion_receipt( + async fn lock_assertion( &self, - request: Request, + request: Request, ) -> Result, Status> { + println_step_heading("2.2".to_string()); println!( - "Got a lock assertion receipt request from {:?} - {:?}", + "Got a LockAssertionRequest from {:?} - {:?}", request.remote_addr(), request ); - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: "xxxxxxxxx".to_string(), - message: format!("Error: Not implemented yet."), - })); - println!("Sending back Ack: {:?}\n", reply); - reply - } -} -pub fn process_transfer_proposal_claims_request( - transfer_proposal_claims_request: TransferProposalClaimsRequest, - conf: config::Config, -) -> Result { - let request_id = - get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); - let is_valid_request = - is_valid_transfer_proposal_claims_request(transfer_proposal_claims_request.clone()); + let lock_assertion_request = request.into_inner().clone(); + let request_id = lock_assertion_request.session_id.to_string(); + let conf = self.config_lock.read().await; - if is_valid_request { - println!("The transfer proposal claims request is valid\n"); - match send_transfer_proposal_receipt_request(transfer_proposal_claims_request, conf) { - Ok(ack) => { - println!("Ack transfer proposal claims request."); - let reply = Ok(ack); - println!("Sending back Ack: {:?}\n", reply); - reply + match log_request_in_remote_satp_db(&request_id, &lock_assertion_request, conf.clone()) { + Ok(_) => { + println!("Successfully stored LockAssertionRequest in remote satp_db with request_id: {}", request_id); } Err(e) => { - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error: Ack transfer proposal claims failed. {:?}", e), - }); + // Internal failure of sled. Send Error response + let error_message = + "Error storing LockAssertionRequest in remote satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; } } - } else { - println!("The transfer proposal claims request is invalid\n"); - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: "Error: The transfer proposal claims request is invalid".to_string(), - }); - } -} - -pub fn process_transfer_proposal_receipt_request( - transfer_proposal_receipt_request: TransferProposalReceiptRequest, - conf: config::Config, -) -> Result { - let request_id = - get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); - let is_valid_request = - is_valid_transfer_proposal_receipt_request(transfer_proposal_receipt_request.clone()); - if is_valid_request { - println!("The transfer proposal receipt request is valid\n"); - match send_transfer_commence_request(transfer_proposal_receipt_request, conf) { + match process_lock_assertion_request(lock_assertion_request, conf.clone()) { Ok(ack) => { - println!("Ack transfer proposal receipt request."); - let reply = Ok(ack); - println!("Sending back Ack: {:?}\n", reply); + let reply = Ok(Response::new(ack)); + println!("Sending Ack of lock assertion request back: {:?}\n", reply); reply } Err(e) => { - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error: Ack transfer proposal receipt failed. {:?}", e), - }); + let error_message = "Lock assertion failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply } } - } else { - println!("The transfer proposal receipt request is invalid\n"); - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: "Error: The transfer proposal receipt request is invalid".to_string(), - }); } -} -/// process_transfer_commence_request is run on the receiver gateway to initiate asset transfer protocol that was -/// requested from the sender gateway -pub fn process_transfer_commence_request( - transfer_commence_request: TransferCommenceRequest, - conf: config::Config, -) -> Result { - let request_id = transfer_commence_request.session_id.to_string(); - let is_valid_request = is_valid_transfer_commence_request(transfer_commence_request.clone()); + async fn lock_assertion_receipt( + &self, + request: Request, + ) -> Result, Status> { + println_step_heading("2.4".to_string()); + println!( + "Got an lock assertion receipt request from {:?} - {:?}", + request.remote_addr(), + request + ); - if is_valid_request { - println!("The transfer commence request is valid\n"); - match send_ack_commence_request(transfer_commence_request, conf) { - Ok(ack) => { - println!("Ack transfer commence request."); - let reply = Ok(ack); - println!("Sending back Ack: {:?}\n", reply); - reply + let lock_assertion_receipt_request = request.into_inner().clone(); + let request_id = lock_assertion_receipt_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = log_request_in_local_satp_db( + &request_id, + &lock_assertion_receipt_request, + conf.clone(), + ); + match request_logged { + Ok(_) => { + println!( + "Successfully stored LockAssertionReceiptRequest in local satp_db with request_id: {}", + request_id + ) } Err(e) => { - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error: Ack commence request failed. {:?}", e), - }); + // Internal failure of sled. Send Error response + let error_message = + "Error storing LockAssertionReceiptRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; } } - } else { - println!("The transfer commence request is invalid\n"); - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: "Error: The transfer commence request is invalid".to_string(), - }); - } -} - -pub fn process_tranfer_proposal_receipt_request( - transfer_proposal_receipt_request: TransferProposalReceiptRequest, - conf: config::Config, -) -> Result { - let request_id = - get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); - let is_valid_request = - is_valid_transfer_proposal_receipt_request(transfer_proposal_receipt_request.clone()); - // TODO some processing - if is_valid_request { - println!("The transfer proposal receipt request is valid\n"); - match send_transfer_commence_request(transfer_proposal_receipt_request, conf) { + match process_lock_assertion_receipt_request(lock_assertion_receipt_request, conf.clone()) { Ok(ack) => { - println!("Ack transfer proposal receipt request."); - let reply = Ok(ack); - println!("Sending back Ack: {:?}\n", reply); + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of lock assertion receipt request back: {:?}\n", + reply + ); reply } Err(e) => { - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error: Ack transfer proposal receipt failed. {:?}", e), - }); + let error_message = "Lock assertion receipt failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply } } - } else { - println!("The transfer proposal receipt request is invalid\n"); - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: "Error: The transfer proposal receipt request is invalid".to_string(), - }); } -} -/// process_ack_commence_request is invoked by the receiver gateway to ack the transfer commence request -/// requested ed by the sender gateway -pub fn process_ack_commence_request( - ack_commence_request: AckCommenceRequest, - conf: config::Config, -) -> Result { - let request_id = ack_commence_request.session_id.to_string(); - let is_valid_request = is_valid_ack_commence_request(ack_commence_request.clone()); + async fn commit_prepare( + &self, + request: Request, + ) -> Result, Status> { + println_step_heading("3.1".to_string()); + println!( + "Got commit prepare request from {:?} - {:?}", + request.remote_addr(), + request + ); - // TODO some processing - if is_valid_request { - println!("The ack commence request is valid\n"); - match send_perform_lock_request(ack_commence_request, conf) { + let commit_prepare_request = request.into_inner().clone(); + let request_id = commit_prepare_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &commit_prepare_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored CommitPrepareRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing CommitPrepareRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_commit_prepare_request(commit_prepare_request, conf.clone()) { Ok(ack) => { - println!("Ack ack commence request."); - let reply = Ok(ack); - println!("Sending back Ack: {:?}\n", reply); + let reply = Ok(Response::new(ack)); + println!("Sending Ack of commit prepare request back: {:?}\n", reply); reply } Err(e) => { - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: format!("Error: perform lock request failed. {:?}", e), - }); + let error_message = "Commit prepare failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply } } - } else { - println!("The ack commence request is invalid\n"); - return Ok(Ack { - status: ack::Status::Error as i32, - request_id: request_id.to_string(), - message: "Error: The ack commence request is invalid".to_string(), - }); } -} -fn send_transfer_proposal_receipt_request( - transfer_proposal_claims_request: TransferProposalClaimsRequest, - conf: config::Config, -) -> Result { - let request_id = + async fn commit_ready( + &self, + request: Request, + ) -> Result, Status> { + println_step_heading("3.3".to_string()); + println!( + "Got commit ready request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let commit_ready_request = request.into_inner().clone(); + let request_id = commit_ready_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &commit_ready_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored CommitReadyRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing CommitReadyRequest in local satp_db for request_id".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_commit_ready_request(commit_ready_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!("Sending Ack of commit ready request back: {:?}\n", reply); + reply + } + Err(e) => { + let error_message = "Commit ready failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn commit_final_assertion( + &self, + request: Request, + ) -> Result, Status> { + println_step_heading("3.5".to_string()); + println!( + "Got commit final assertion request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let commit_final_assertion_request = request.into_inner().clone(); + let request_id = commit_final_assertion_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = log_request_in_local_satp_db( + &request_id, + &commit_final_assertion_request, + conf.clone(), + ); + match request_logged { + Ok(_) => { + println!( + "Successfully stored CommitFinalAssertionRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing CommitFinalAssertionRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_commit_final_assertion_request(commit_final_assertion_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of commit final assertion request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Commit final assertion failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn ack_final_receipt( + &self, + request: Request, + ) -> Result, Status> { + println_step_heading("3.7".to_string()); + println!( + "Got commit final assertion request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let ack_final_receipt_request = request.into_inner().clone(); + let request_id = ack_final_receipt_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &ack_final_receipt_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored AckFinalReceiptRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing AckFinalReceiptRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + match process_ack_final_receipt_request(ack_final_receipt_request, conf.clone()) { + Ok(ack) => { + let reply = Ok(Response::new(ack)); + println!( + "Sending Ack of ack final receipt request back: {:?}\n", + reply + ); + reply + } + Err(e) => { + let error_message = "Ack final receipt failed.".to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + reply + } + } + } + + async fn transfer_completed( + &self, + request: Request, + ) -> Result, Status> { + println_step_heading("3.9".to_string()); + println!( + "Got commit final assertion request from {:?} - {:?}", + request.remote_addr(), + request + ); + + let transfer_completed_request = request.into_inner().clone(); + let request_id = transfer_completed_request.session_id.to_string(); + let conf = self.config_lock.read().await; + + // TODO refactor + let request_logged: Result, Error> = + log_request_in_local_satp_db(&request_id, &transfer_completed_request, conf.clone()); + match request_logged { + Ok(_) => { + println!( + "Successfully stored TransferCompletedRequest in local satp_db with request_id: {}", + request_id + ) + } + Err(e) => { + // Internal failure of sled. Send Error response + let error_message = + "Error storing TransferCompletedRequest in local satp_db for request_id" + .to_string(); + let reply = create_ack_error_message(request_id, error_message, e); + return reply; + } + } + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Transfer Completed request".to_string(), + }; + return Ok(Response::new(reply)); + } +} + +pub fn process_transfer_proposal_claims_request( + transfer_proposal_claims_request: TransferProposalClaimsRequest, + conf: config::Config, +) -> Result { + let request_id = get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); + let is_valid_request = + is_valid_transfer_proposal_claims_request(transfer_proposal_claims_request.clone()); + + if is_valid_request { + println!("The transfer proposal claims request is valid\n"); + let transfer_proposal_receipt_request = + create_transfer_proposal_receipt_request(transfer_proposal_claims_request.clone()); + match send_transfer_proposal_receipt_request(transfer_proposal_receipt_request, conf) { + Ok(ack) => { + println!("Ack transfer proposal claims request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: Ack transfer proposal claims failed. {:?}", e), + }); + } + } + } else { + println!("The transfer proposal claims request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The transfer proposal claims request is invalid".to_string(), + }); + } +} + +pub fn process_transfer_proposal_receipt_request( + transfer_proposal_receipt_request: TransferProposalReceiptRequest, + conf: config::Config, +) -> Result { + let request_id = + get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); + let is_valid_request = + is_valid_transfer_proposal_receipt_request(transfer_proposal_receipt_request.clone()); + + if is_valid_request { + println!("The transfer proposal receipt request is valid\n"); + let transfer_commence_request = + create_transfer_commence_request(transfer_proposal_receipt_request.clone()); + match send_transfer_commence_request(transfer_commence_request, conf) { + Ok(ack) => { + println!("Ack transfer proposal receipt request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: Ack transfer proposal receipt failed. {:?}", e), + }); + } + } + } else { + println!("The transfer proposal receipt request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The transfer proposal receipt request is invalid".to_string(), + }); + } +} + +/// process_transfer_commence_request is run on the receiver gateway to initiate asset transfer protocol that was +/// requested from the sender gateway +pub fn process_transfer_commence_request( + transfer_commence_request: TransferCommenceRequest, + conf: config::Config, +) -> Result { + let request_id = transfer_commence_request.session_id.to_string(); + let is_valid_request = is_valid_transfer_commence_request(transfer_commence_request.clone()); + + if is_valid_request { + println!("The transfer commence request is valid\n"); + let ack_commence_request = create_ack_commence_request(transfer_commence_request.clone()); + match send_ack_commence_request(ack_commence_request, conf) { + Ok(ack) => { + println!("Ack transfer commence request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: Ack commence request failed. {:?}", e), + }); + } + } + } else { + println!("The transfer commence request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The transfer commence request is invalid".to_string(), + }); + } +} + +/// process_ack_commence_request is invoked by the receiver gateway to ack the transfer commence request +/// requested ed by the sender gateway +pub fn process_ack_commence_request( + ack_commence_request: AckCommenceRequest, + conf: config::Config, +) -> Result { + let request_id = ack_commence_request.session_id.to_string(); + let is_valid_request = is_valid_ack_commence_request(ack_commence_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The ack commence request is valid\n"); + let perform_lock_request: PerformLockRequest = + create_perform_lock_request(ack_commence_request); + match send_perform_lock_request(perform_lock_request, conf) { + Ok(ack) => { + println!("Ack ack commence request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: perform lock request failed. {:?}", e), + }); + } + } + } else { + println!("The ack commence request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The ack commence request is invalid".to_string(), + }); + } +} + +pub fn process_send_asset_status_request( + send_asset_status_request: SendAssetStatusRequest, + conf: config::Config, +) -> Result { + let request_id = send_asset_status_request.session_id.to_string(); + let is_valid_request = is_valid_send_asset_status_request(send_asset_status_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The send asset status request is valid\n"); + + let result; + let status = send_asset_status_request.status.as_str(); + match status { + "Locked" => { + println_step_heading("2.1B".to_string()); + println!("Received asset status as Locked. Sending the lock assertion request"); + let lock_assertion_request = + create_lock_assertion_request(send_asset_status_request); + result = send_lock_assertion_request(lock_assertion_request, conf) + } + "Created" => { + println_step_heading("3.2B".to_string()); + println!("Received asset status as Created. Sending the commit ready request"); + let commit_ready_request = create_commit_ready_request(send_asset_status_request); + result = send_commit_ready_request(commit_ready_request, conf); + } + "Extinguished" => { + println_step_heading("3.4B".to_string()); + println!("Received asset status as Extinguished. Sending the commit final assertion request"); + let commit_final_assertion_request = + create_commit_final_assertion_request(send_asset_status_request); + result = send_commit_final_assertion_request(commit_final_assertion_request, conf) + } + "Finalized" => { + println_step_heading("3.6B".to_string()); + println!( + "Received asset status as Finalized. Sending the ack final receipt request" + ); + let ack_final_receipt_request = + create_ack_final_receipt_request(send_asset_status_request.clone()); + result = send_ack_final_receipt_request(ack_final_receipt_request, conf) + } + _ => result = Err(Error::Simple(format!("Invalid asset status: {}", status))), + } + + match result { + Ok(ack) => { + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: sending request failed. {:?}", e), + }); + } + } + } else { + println!("The send asset status request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The send asset status request is invalid".to_string(), + }); + } +} + +pub fn process_lock_assertion_request( + lock_assertion_request: LockAssertionRequest, + conf: config::Config, +) -> Result { + let request_id = lock_assertion_request.session_id.to_string(); + let is_valid_request = is_valid_lock_assertion_request(lock_assertion_request.clone()); + + if is_valid_request { + println!("The lock assertion request is valid\n"); + match send_lock_assertion_broadcast_request(lock_assertion_request, conf) { + Ok(ack) => { + println!("Ack lock assertion request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: Ack lock assertion failed. {:?}", e), + }); + } + } + } else { + println!("The lock assertion request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The lock assertion request is invalid".to_string(), + }); + } +} + +pub fn process_lock_assertion_receipt_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, + conf: config::Config, +) -> Result { + let request_id = lock_assertion_receipt_request.session_id.to_string(); + let is_valid_request = + is_valid_lock_assertion_receipt_request(lock_assertion_receipt_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The lock assertion receipt request is valid\n"); + let commit_prepare_request = + create_commit_prepare_request(lock_assertion_receipt_request.clone()); + match send_commit_prepare_request(commit_prepare_request, conf) { + Ok(ack) => { + println!("Ack lock assertion receipt request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: perform lock request failed. {:?}", e), + }); + } + } + } else { + println!("The lock assertion receipt request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The lock assertion receipt request is invalid".to_string(), + }); + } +} + +pub fn process_commit_prepare_request( + commit_prepare_request: CommitPrepareRequest, + conf: config::Config, +) -> Result { + let request_id = commit_prepare_request.session_id.to_string(); + let is_valid_request = is_valid_commit_prepare_request(commit_prepare_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The commit prepare request is valid\n"); + let create_asset_request: CreateAssetRequest = + create_create_asset_request(commit_prepare_request); + match send_create_asset_request(create_asset_request, conf) { + Ok(ack) => { + println!("Ack commit prepare request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: commit prepare request failed. {:?}", e), + }); + } + } + } else { + println!("The commit prepare request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The commit prepare request is invalid".to_string(), + }); + } +} + +pub fn process_commit_ready_request( + commit_ready_request: CommitReadyRequest, + conf: config::Config, +) -> Result { + let request_id = commit_ready_request.session_id.to_string(); + let is_valid_request = is_valid_commit_ready_request(commit_ready_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The commit ready request is valid\n"); + let extinguish_request: ExtinguishRequest = create_extinguish_request(commit_ready_request); + match send_extinguish_request(extinguish_request, conf) { + Ok(ack) => { + println!("Ack commit ready request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: commit ready request failed. {:?}", e), + }); + } + } + } else { + println!("The commit ready request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The commit ready request is invalid".to_string(), + }); + } +} + +pub fn process_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + conf: config::Config, +) -> Result { + let request_id = commit_final_assertion_request.session_id.to_string(); + let is_valid_request = + is_valid_commit_final_assertion_request(commit_final_assertion_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The commit final assertion request is valid\n"); + let assign_asset_request: AssignAssetRequest = + create_assign_asset_request(commit_final_assertion_request); + match send_assign_asset_request(assign_asset_request, conf) { + Ok(ack) => { + println!("Ack commit final assertion request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: commit final assertion request failed. {:?}", e), + }); + } + } + } else { + println!("The commit final assertion request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The commit final assertion request is invalid".to_string(), + }); + } +} + +pub fn process_ack_final_receipt_request( + ack_final_receipt_request: AckFinalReceiptRequest, + conf: config::Config, +) -> Result { + let request_id = ack_final_receipt_request.session_id.to_string(); + let is_valid_request = is_valid_ack_final_receipt_request(ack_final_receipt_request.clone()); + + // TODO some processing + if is_valid_request { + println!("The ack final receipt request is valid\n"); + match send_ack_final_receipt_broadcast_request(ack_final_receipt_request, conf) { + Ok(ack) => { + println!("Ack ack final receipt request."); + let reply = Ok(ack); + println!("Sending back Ack: {:?}\n", reply); + reply + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!("Error: ack final receipt request failed. {:?}", e), + }); + } + } + } else { + println!("The ack final receipt request is invalid\n"); + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: "Error: The ack final receipt request is invalid".to_string(), + }); + } +} + +fn send_transfer_proposal_receipt_request( + transfer_proposal_receipt_request: TransferProposalReceiptRequest, + conf: config::Config, +) -> Result { + let request_id = + get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); let (relay_host, relay_port) = - get_relay_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + get_relay_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let transfer_proposal_receipt_request = - create_transfer_proposal_receipt_request(transfer_proposal_claims_request.clone()); spawn_send_transfer_proposal_receipt_request( transfer_proposal_receipt_request, relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -491,24 +1133,21 @@ fn send_transfer_proposal_receipt_request( } fn send_transfer_commence_request( - transfer_proposal_receipt_request: TransferProposalReceiptRequest, + transfer_commence_request: TransferCommenceRequest, conf: config::Config, ) -> Result { - let request_id = - get_request_id_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); + let request_id = transfer_commence_request.session_id.clone(); let (relay_host, relay_port) = - get_relay_from_transfer_proposal_receipt(transfer_proposal_receipt_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + get_relay_from_transfer_commence(transfer_commence_request.clone()); + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let transfer_commence_request = - create_transfer_commence_request(transfer_proposal_receipt_request.clone()); spawn_send_transfer_commence_request( transfer_commence_request, relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -520,22 +1159,20 @@ fn send_transfer_commence_request( } fn send_ack_commence_request( - transfer_commence_request: TransferCommenceRequest, + ack_commence_request: AckCommenceRequest, conf: config::Config, ) -> Result { - let request_id = &transfer_commence_request.session_id.to_string(); - let (relay_host, relay_port) = - get_relay_from_transfer_commence(transfer_commence_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + let request_id = &ack_commence_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_ack_commence(ack_commence_request.clone()); + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let ack_commence_request = create_ack_commence_request(transfer_commence_request.clone()); spawn_send_ack_commence_request( ack_commence_request, relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); let reply = Ack { @@ -546,28 +1183,331 @@ fn send_ack_commence_request( return Ok(reply); } +fn send_lock_assertion_request( + lock_assertion_request: LockAssertionRequest, + conf: config::Config, +) -> Result { + let request_id = &lock_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_lock_assertion_request( + lock_assertion_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Send Asset Status request".to_string(), + }; + return Ok(reply); +} + +fn send_lock_assertion_broadcast_request( + lock_assertion_request: LockAssertionRequest, + conf: config::Config, +) -> Result { + println_step_heading("2.3".to_string()); + + let request_id = &lock_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_lock_assertion(lock_assertion_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_lock_assertion_broadcast_request( + lock_assertion_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Lock Assertion request".to_string(), + }; + return Ok(reply); +} + fn send_perform_lock_request( - ack_commence_request: AckCommenceRequest, + perform_lock_request: PerformLockRequest, conf: config::Config, ) -> Result { - let request_id = &ack_commence_request.session_id.to_string(); - let (relay_host, relay_port) = get_relay_from_ack_commence(ack_commence_request.clone()); - let (use_tls, relay_tlsca_cert_path) = + println_stage_heading("2".to_string()); + println_step_heading("2.1A".to_string()); + + let request_id = &perform_lock_request.session_id.to_string(); + let driver_address = get_driver_address_from_perform_lock(perform_lock_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); + match result { + Ok(driver_info) => { + spawn_send_perform_lock_request(driver_info, perform_lock_request); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the ack commence request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the ack commence request failed. Driver not found {:?}", + e + ), + }); + } + } +} + +fn send_commit_prepare_request( + commit_prepare_request: CommitPrepareRequest, + conf: config::Config, +) -> Result { + println_stage_heading("3".to_string()); + let request_id = &commit_prepare_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_commit_prepare(commit_prepare_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_commit_prepare_request( + commit_prepare_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the Lock Assertion request".to_string(), + }; + return Ok(reply); +} + +fn send_commit_ready_request( + commit_ready_request: CommitReadyRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_ready_request.session_id.to_string(); + let (relay_host, relay_port) = get_relay_from_commit_ready(commit_ready_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_commit_ready_request( + commit_ready_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); +} + +fn send_create_asset_request( + create_asset_request: CreateAssetRequest, + conf: config::Config, +) -> Result { + // TODO + println_step_heading("3.2A".to_string()); + + let request_id = &create_asset_request.session_id.to_string(); + let driver_address = get_driver_address_from_create_asset(create_asset_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); + + match result { + Ok(driver_info) => { + spawn_send_create_asset_request(driver_info, create_asset_request); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the commit prepare request failed. Driver not found {:?}", + e + ), + }); + } + } +} + +fn send_extinguish_request( + extinguish_request: ExtinguishRequest, + conf: config::Config, +) -> Result { + // TODO + println_step_heading("3.4A".to_string()); + let request_id = &extinguish_request.session_id.to_string(); + let driver_address = get_driver_address_from_extinguish(extinguish_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); + + match result { + Ok(driver_info) => { + spawn_send_extinguish_request(driver_info, extinguish_request); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit prepare request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the commit prepare request failed. Driver not found {:?}", + e + ), + }); + } + } +} + +fn send_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &commit_final_assertion_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_commit_final_assertion(commit_final_assertion_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_commit_final_assertion_request( + commit_final_assertion_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Commit final assertion request sent".to_string(), + }; + return Ok(reply); +} + +fn send_ack_final_receipt_request( + ack_final_receipt_request: AckFinalReceiptRequest, + conf: config::Config, +) -> Result { + // TODO + let request_id = &ack_final_receipt_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); + let (use_tls, tlsca_cert_path) = + get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); + + spawn_send_ack_final_receipt_request( + ack_final_receipt_request, + relay_host, + relay_port, + use_tls, + tlsca_cert_path, + conf, + ); + + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack final receipt request sent".to_string(), + }; + return Ok(reply); +} + +fn send_assign_asset_request( + assign_asset_request: AssignAssetRequest, + conf: config::Config, +) -> Result { + // TODO + println_step_heading("3.6A".to_string()); + let request_id = &assign_asset_request.session_id.to_string(); + let driver_address = get_driver_address_from_assign_asset(assign_asset_request.clone()); + let parsed_address = parse_address(driver_address)?; + let result = get_driver(parsed_address.network_id.to_string(), conf.clone()); + + match result { + Ok(driver_info) => { + spawn_send_assign_asset_request(driver_info, assign_asset_request); + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: request_id.to_string(), + message: "Ack of the commit final assertion request".to_string(), + }; + return Ok(reply); + } + Err(e) => { + return Ok(Ack { + status: ack::Status::Error as i32, + request_id: request_id.to_string(), + message: format!( + "Error: Ack of the commit final assertion request failed. Driver not found {:?}", + e + ), + }); + } + } +} + +fn send_ack_final_receipt_broadcast_request( + ack_final_receipt_request: AckFinalReceiptRequest, + conf: config::Config, +) -> Result { + // TODO + println_step_heading("3.8".to_string()); + let request_id = &ack_final_receipt_request.session_id.to_string(); + let (relay_host, relay_port) = + get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); + let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let perfrom_lock_request = create_lock_assertion_request(ack_commence_request.clone()); + let transfer_completed_request = + create_transfer_completed_request(ack_final_receipt_request.clone()); - spawn_send_perform_lock_request( - perfrom_lock_request, + spawn_send_ack_final_receipt_broadcast_request( + ack_final_receipt_request, relay_host, relay_port, use_tls, - relay_tlsca_cert_path, + tlsca_cert_path, conf, ); + let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), - message: "Ack of the ack commence request".to_string(), + message: "Ack of the commit prepare request".to_string(), }; return Ok(reply); } @@ -595,3 +1535,49 @@ fn is_valid_ack_commence_request(ack_commence_request: AckCommenceRequest) -> bo //TODO true } + +fn is_valid_lock_assertion_request(lock_assertion_request: LockAssertionRequest) -> bool { + //TODO + true +} + +fn is_valid_lock_assertion_receipt_request( + lock_assertion_receipt_request: LockAssertionReceiptRequest, +) -> bool { + //TODO + true +} + +fn is_valid_commit_prepare_request(commit_prepare_request: CommitPrepareRequest) -> bool { + //TODO + true +} + +fn is_valid_commit_ready_request(commit_ready_request: CommitReadyRequest) -> bool { + //TODO + true +} + +fn is_valid_commit_final_assertion_request( + commit_final_assertion_request: CommitFinalAssertionRequest, +) -> bool { + //TODO + true +} + +fn is_valid_ack_final_receipt_request(ack_final_receipt_request: AckFinalReceiptRequest) -> bool { + //TODO + true +} + +fn is_valid_transfer_completed_request( + transfer_completed_request: TransferCompletedRequest, +) -> bool { + //TODO + true +} + +fn is_valid_send_asset_status_request(send_asset_status_request: SendAssetStatusRequest) -> bool { + //TODO + true +} diff --git a/weaver/samples/fabric/satpsimpleasset/.gitignore b/weaver/samples/fabric/satpsimpleasset/.gitignore new file mode 100644 index 0000000000..6e83e63f95 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/.gitignore @@ -0,0 +1,4 @@ +satpsimpleasset +asset-mgmt +mocks +vendor diff --git a/weaver/samples/fabric/satpsimpleasset/Makefile b/weaver/samples/fabric/satpsimpleasset/Makefile new file mode 100644 index 0000000000..0b11edb7ab --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/Makefile @@ -0,0 +1,27 @@ +run-vendor: + go mod edit -replace github.com/hyperledger/cacti/weaver/common/protos-go/v2=../../../common/protos-go/ + go mod edit -replace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2=../../../core/network/fabric-interop-cc/interfaces/asset-mgmt/ + go mod edit -replace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils=../../../core/network/fabric-interop-cc/libs/testutils/ + go mod vendor + +undo-vendor: + rm -rf vendor + go mod edit -dropreplace github.com/hyperledger/cacti/weaver/common/protos-go/v2 + go mod edit -dropreplace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 + go mod edit -dropreplace github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils + +build-local: run-vendor build undo-vendor + +test-local: run-vendor test undo-vendor + +build: + go build -v . + +test: + go test -v . + +clean-vendor: + rm -rf vendor + +clean: clean-vendor + rm satpsimpleasset diff --git a/weaver/samples/fabric/satpsimpleasset/assetmgmt.go b/weaver/samples/fabric/satpsimpleasset/assetmgmt.go new file mode 100644 index 0000000000..384c4c3c96 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/assetmgmt.go @@ -0,0 +1,360 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package main + +import ( + "encoding/json" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/cacti/weaver/common/protos-go/v2/common" + "github.com/hyperledger/fabric-contract-api-go/contractapi" + log "github.com/sirupsen/logrus" +) + +// asset specific checks (ideally an asset in a different application might implement checks specific to that asset) +func (s *SmartContract) BondAssetSpecificChecks(ctx contractapi.TransactionContextInterface, assetType, id string, lockInfoSerializedProto64 string) error { + + lockInfo, err := s.amc.ValidateAndExtractLockInfo(lockInfoSerializedProto64) + if err != nil { + return err + } + lockInfoHTLC := &common.AssetLockHTLC{} + err = proto.Unmarshal(lockInfo.LockInfo, lockInfoHTLC) + if err != nil { + return logThenErrorf("unmarshal error: %+v", err) + } + // ReadAsset should check both the existence and ownership of the asset for the locker + bond, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return logThenErrorf("failed reading the bond asset: %+v", err) + } + log.Infof("bond: %+v", *bond) + log.Infof("lockInfoHTLC: %+v", *lockInfoHTLC) + + // Check if asset doesn't mature before locking period + if uint64(bond.MaturityDate.Unix()) < lockInfoHTLC.ExpiryTimeSecs { + return logThenErrorf("cannot lock bond asset as it will mature before locking period") + } + + return nil +} + +// Ledger transaction (invocation) functions + +func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) { + + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetExchangeAgreementSerializedProto64) + if err != nil { + return "", err + } + err = s.BondAssetSpecificChecks(ctx, assetAgreement.AssetType, assetAgreement.Id, lockInfoSerializedProto64) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + contractId, err := s.amc.LockAsset(ctx, assetExchangeAgreementSerializedProto64, lockInfoSerializedProto64) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + // write to the ledger the details needed at the time of unlock/claim + err = s.amc.ContractIdAssetsLookupMap(ctx, assetAgreement.AssetType, assetAgreement.Id, contractId) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + return contractId, nil +} + +func (s *SmartContract) LockFungibleAsset(ctx contractapi.TransactionContextInterface, fungibleAssetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error) { + + assetAgreement, err := s.amc.ValidateAndExtractFungibleAssetAgreement(fungibleAssetExchangeAgreementSerializedProto64) + if err != nil { + return "", err + } + lockInfo, err := s.amc.ValidateAndExtractLockInfo(lockInfoSerializedProto64) + if err != nil { + return "", err + } + lockInfoHTLC := &common.AssetLockHTLC{} + err = proto.Unmarshal(lockInfo.LockInfo, lockInfoHTLC) + if err != nil { + return "", logThenErrorf("unmarshal error: %+v", err) + } + + // Check if locker/transaction-creator has enough quantity of token assets to lock + lockerHasEnoughTokens, err := s.TokenAssetsExist(ctx, assetAgreement.AssetType, assetAgreement.NumUnits) + if err != nil { + return "", logThenErrorf(err.Error()) + } + if !lockerHasEnoughTokens { + return "", logThenErrorf("cannot lock token asset of type %s as there are not enough tokens", assetAgreement.AssetType) + } + + contractId, err := s.amc.LockFungibleAsset(ctx, fungibleAssetExchangeAgreementSerializedProto64, lockInfoSerializedProto64) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + err = s.DeleteTokenAssets(ctx, assetAgreement.AssetType, assetAgreement.NumUnits) + if err != nil { + // not performing the operation UnlockFungibleAsset and let the TxCreator take care of it + return contractId, logThenErrorf(err.Error()) + } + + err = s.amc.ContractIdFungibleAssetsLookupMap(ctx, assetAgreement.AssetType, assetAgreement.NumUnits, contractId) + if err != nil { + return "", logThenErrorf(err.Error()) + } + + return contractId, nil +} + +// Check whether this asset has been locked by anyone (not just by caller) +func (s *SmartContract) IsAssetLocked(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string) (bool, error) { + return s.amc.IsAssetLocked(ctx, assetAgreementSerializedProto64) +} + +// Check whether a bond asset has been locked using contractId by anyone (not just by caller) +func (s *SmartContract) IsAssetLockedQueryUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + return s.amc.IsAssetLockedQueryUsingContractId(ctx, contractId) +} + +// Check whether a token asset has been locked using contractId by anyone (not just by caller) +func (s *SmartContract) IsFungibleAssetLocked(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + return s.amc.IsFungibleAssetLocked(ctx, contractId) +} + +func (s *SmartContract) ClaimAsset(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string, claimInfoSerializedProto64 string) (bool, error) { + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetAgreementSerializedProto64) + if err != nil { + return false, err + } + claimed, err := s.amc.ClaimAsset(ctx, assetAgreementSerializedProto64, claimInfoSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if claimed { + // Change asset ownership to claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset, err := getBondAsset(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset.Owner = string(recipientECertBase64) + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = ctx.GetStub().PutState(getBondAssetKey(assetAgreement.AssetType, assetAgreement.Id), assetJSON) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + err = s.amc.DeleteAssetLookupMaps(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf("failed to delete bond asset lookup maps: %+v", err) + } + + return true, nil + } else { + return false, logThenErrorf("claim on bond asset type %s with asset id %s failed", assetAgreement.AssetType, assetAgreement.Id) + } +} + +func (s *SmartContract) AssignAsset(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string, claimInfoSerializedProto64 string) (bool, error) { + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetAgreementSerializedProto64) + if err != nil { + return false, err + } + + // Change asset ownership to claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset, err := getBondAsset(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset.Owner = string(recipientECertBase64) + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = ctx.GetStub().PutState(getBondAssetKey(assetAgreement.AssetType, assetAgreement.Id), assetJSON) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + return true, nil +} + +func (s *SmartContract) ClaimAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) { + claimed, err := s.amc.ClaimAssetUsingContractId(ctx, contractId, claimInfoSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if claimed { + // Change asset ownership to claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + // Fetch the contracted bond asset type and id from the ledger + assetType, assetId, err := s.amc.FetchFromContractIdAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + asset, err := getBondAsset(ctx, assetType, assetId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + asset.Owner = recipientECertBase64 + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = ctx.GetStub().PutState(getBondAssetKey(assetType, assetId), assetJSON) + if err != nil { + return false, logThenErrorf(err.Error()) + } + // delete the lookup maps + err = s.amc.DeleteAssetLookupMapsUsingContractId(ctx, assetType, assetId, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + return true, nil + } else { + return false, logThenErrorf("claim on bond asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) ClaimFungibleAsset(ctx contractapi.TransactionContextInterface, contractId, claimInfoSerializedProto64 string) (bool, error) { + claimed, err := s.amc.ClaimFungibleAsset(ctx, contractId, claimInfoSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if claimed { + // Add the claimed tokens into the wallet of the claimant + recipientECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + // Fetch the contracted token asset type and numUnits from the ledger + assetType, numUnits, err := s.amc.FetchFromContractIdFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + err = s.IssueTokenAssets(ctx, assetType, numUnits, recipientECertBase64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = s.amc.DeleteFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + return true, nil + } else { + return false, logThenErrorf("claim on token asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) UnlockAsset(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string) (bool, error) { + assetAgreement, err := s.amc.ValidateAndExtractAssetAgreement(assetAgreementSerializedProto64) + if err != nil { + return false, err + } + + unlocked, err := s.amc.UnlockAsset(ctx, assetAgreementSerializedProto64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if unlocked { + err = s.amc.DeleteAssetLookupMaps(ctx, assetAgreement.AssetType, assetAgreement.Id) + if err != nil { + return false, logThenErrorf("failed to delete bond asset lookup maps: %+v", err) + } + } else { + return false, logThenErrorf("unlock on bond asset type %s with asset id %s failed", assetAgreement.AssetType, assetAgreement.Id) + } + + return true, nil +} + +func (s *SmartContract) UnlockAssetUsingContractId(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + unlocked, err := s.amc.UnlockAssetUsingContractId(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if unlocked { + // delete the lookup maps + err := s.amc.DeleteAssetLookupMapsOnlyUsingContractId(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + return true, nil + } else { + return false, logThenErrorf("unlock on bond asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) UnlockFungibleAsset(ctx contractapi.TransactionContextInterface, contractId string) (bool, error) { + unlocked, err := s.amc.UnlockFungibleAsset(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + if unlocked { + // Add the unlocked tokens into the wallet of the locker + lockerECertBase64, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + // Fetch the contracted token asset type and numUnits from the ledger + assetType, numUnits, err := s.amc.FetchFromContractIdFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + + err = s.IssueTokenAssets(ctx, assetType, numUnits, lockerECertBase64) + if err != nil { + return false, logThenErrorf(err.Error()) + } + err = s.amc.DeleteFungibleAssetLookupMap(ctx, contractId) + if err != nil { + return false, logThenErrorf(err.Error()) + } + return true, nil + } else { + return false, logThenErrorf("unlock on token asset using contractId %s failed", contractId) + } +} + +func (s *SmartContract) GetHTLCHash(ctx contractapi.TransactionContextInterface, assetAgreementBytesBase64 string) (string, error) { + return s.amc.GetHTLCHash(ctx, assetAgreementBytesBase64) +} + +func (s *SmartContract) GetHTLCHashByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) { + return s.amc.GetHTLCHashByContractId(ctx, contractId) +} + +func (s *SmartContract) GetHTLCHashPreImage(ctx contractapi.TransactionContextInterface, assetAgreementBytesBase64 string) (string, error) { + return s.amc.GetHTLCHashPreImage(ctx, assetAgreementBytesBase64) +} + +func (s *SmartContract) GetHTLCHashPreImageByContractId(ctx contractapi.TransactionContextInterface, contractId string) (string, error) { + return s.amc.GetHTLCHashPreImageByContractId(ctx, contractId) +} diff --git a/weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go b/weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go new file mode 100644 index 0000000000..83db59decd --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/assetmgmt_test.go @@ -0,0 +1,232 @@ +package main_test + +import ( + "encoding/json" + "encoding/base64" + "crypto/sha256" + "fmt" + "testing" + "time" + + mspProtobuf "github.com/hyperledger/fabric-protos-go/msp" + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric-chaincode-go/shim" + "github.com/stretchr/testify/require" + sa "github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset" + "github.com/hyperledger/cacti/weaver/common/protos-go/v2/common" + wtest "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils" +) + +// function that supplies value that is to be returned by ctx.GetStub().GetCreator() in locker/recipient context +func getCreatorInContext(creator string) string { + serializedIdentity := &mspProtobuf.SerializedIdentity{} + var eCertBytes []byte + if creator == "locker" { + eCertBytes, _ = base64.StdEncoding.DecodeString(getLockerECertBase64()) + } else { + eCertBytes, _ = base64.StdEncoding.DecodeString(getRecipientECertBase64()) + } + serializedIdentity.IdBytes = eCertBytes + serializedIdentity.Mspid = "ca.org1.example.com" + serializedIdentityBytes, _ := proto.Marshal(serializedIdentity) + + return string(serializedIdentityBytes) +} + +// function that supplies the ECert in base64 for locker (e.g., Alice) +func getLockerECertBase64() string { + eCertBase64 := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNyVENDQWxTZ0F3SUJBZ0lVSENXLzBtV0xhc2hISG9zd0xxVWhpK1FwREc4d0NnWUlLb1pJemowRUF3SXcKY2pFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1ROHdEUVlEVlFRSApFd1pFZFhKb1lXMHhHakFZQmdOVkJBb1RFVzl5WnpFdWJtVjBkMjl5YXpFdVkyOXRNUjB3R3dZRFZRUURFeFJqCllTNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQWVGdzB5TURBM01qa3dORE0yTURCYUZ3MHlNVEEzTWprd05EUXgKTURCYU1GMHhDekFKQmdOVkJBWVRBbFZUTVJjd0ZRWURWUVFJRXc1T2IzSjBhQ0JEWVhKdmJHbHVZVEVVTUJJRwpBMVVFQ2hNTFNIbHdaWEpzWldSblpYSXhEekFOQmdOVkJBc1RCbU5zYVdWdWRERU9NQXdHQTFVRUF4TUZkWE5sCmNqRXdXVEFUQmdjcWhrak9QUUlCQmdncWhrak9QUU1CQndOQ0FBU3VoL3JWQ2Y4T0R1dzBJaG5yTTJpaWYyYTcKc0dUOEJJVjFQRURVM1NucUNsbWgrUlYvM0p5S2wvVHl0aHpOL1pWbktFL3R2NWQzZ1ZXYk5zdGM5NytTbzRIYwpNSUhaTUE0R0ExVWREd0VCL3dRRUF3SUhnREFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCUXgvaExZCkNORzRlekNxdmdUS0MvV3d1U1ZubURBZkJnTlZIU01FR0RBV2dCVFdENjArZUNIYkR5RDMzUFdiQ3hWdVFxTUEKcVRBZkJnTlZIUkVFR0RBV2doUnZZelV4TURNM05EY3pPREF1YVdKdExtTnZiVEJZQmdncUF3UUZCZ2NJQVFSTQpleUpoZEhSeWN5STZleUpvWmk1QlptWnBiR2xoZEdsdmJpSTZJaUlzSW1obUxrVnVjbTlzYkcxbGJuUkpSQ0k2CkluVnpaWEl4SWl3aWFHWXVWSGx3WlNJNkltTnNhV1Z1ZENKOWZUQUtCZ2dxaGtqT1BRUURBZ05IQURCRUFpQUYKbnNMNlV1eFRtSks5bmhkTU1QNWxWN3hueVlsMVd5RGl6RVFzZnd1T1p3SWdYY3duSE9hVURXWWpmWHRGU0k1eQp6WjltcjZQRWtSNER0VEhJUkZhTVYxOD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==" + + return eCertBase64 +} + +// function that supplies the ECert in base64 for recipient (e.g., Bob) +func getRecipientECertBase64() string { + eCertBase64 := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNzekNDQWxxZ0F3SUJBZ0lVSjk3ZDJaWUNkRkNHbFo5L3hmZHRlcUdMc1Jvd0NnWUlLb1pJemowRUF3SXcKY2pFTE1Ba0dBMVVFQmhNQ1ZWTXhGekFWQmdOVkJBZ1REazV2Y25Sb0lFTmhjbTlzYVc1aE1ROHdEUVlEVlFRSApFd1pFZFhKb1lXMHhHakFZQmdOVkJBb1RFVzl5WnpFdWJtVjBkMjl5YXpFdVkyOXRNUjB3R3dZRFZRUURFeFJqCllTNXZjbWN4TG01bGRIZHZjbXN4TG1OdmJUQWVGdzB5TURBM01qa3dORE0yTURCYUZ3MHlNVEEzTWprd05EUXgKTURCYU1HQXhDekFKQmdOVkJBWVRBbFZUTVJjd0ZRWURWUVFJRXc1T2IzSjBhQ0JEWVhKdmJHbHVZVEVVTUJJRwpBMVVFQ2hNTFNIbHdaWEpzWldSblpYSXhEakFNQmdOVkJBc1RCV0ZrYldsdU1SSXdFQVlEVlFRREV3bHZjbWN4CllXUnRhVzR3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFmbjRmVHRDclQ3WVMrZVI1WWRFVU8KMHRKWmJGaEtyYUdqeWVNM2tBTzNNN1VHdVBsUCtXcFdjNkNYUEx3bTNETHgrcjFhMUx6eW1KUWdaOVJjdXErcgpvNEhmTUlIY01BNEdBMVVkRHdFQi93UUVBd0lIZ0RBTUJnTlZIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlM2ClkxR1FCMXAwUlNBeWxjTTRxQTlZS0JkU2hEQWZCZ05WSFNNRUdEQVdnQlRXRDYwK2VDSGJEeUQzM1BXYkN4VnUKUXFNQXFUQWZCZ05WSFJFRUdEQVdnaFJ2WXpVeE1ETTNORGN6T0RBdWFXSnRMbU52YlRCYkJnZ3FBd1FGQmdjSQpBUVJQZXlKaGRIUnljeUk2ZXlKb1ppNUJabVpwYkdsaGRHbHZiaUk2SWlJc0ltaG1Ma1Z1Y205c2JHMWxiblJKClJDSTZJbTl5WnpGaFpHMXBiaUlzSW1obUxsUjVjR1VpT2lKaFpHMXBiaUo5ZlRBS0JnZ3Foa2pPUFFRREFnTkgKQURCRUFpQkwrSzAzVGFFeWJaRkdWMmMzSS81ZXlpMFBveGc2elZOWDJkajJWRlk5WWdJZ0w5ZlhzcWhaUEU0VApBSkU4ZVZqdWZaOVJnNERJWWloTVVTKzBPbGpWL3pBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t" + return eCertBase64 +} + +// function to generate a "SHA256" hash in base64 format for a given preimage +func generateSHA256HashInBase64Form(preimage string) string { + hasher := sha256.New() + hasher.Write([]byte(preimage)) + shaHash := hasher.Sum(nil) + shaHashBase64 := base64.StdEncoding.EncodeToString(shaHash) + return shaHashBase64 +} + +type ContractedFungibleAsset struct { + Type string `json:"type"` + NumUnits uint64 `json:"id"` +} + +// test case for "asset exchange" happy path +func TestExchangeBondAssetWithTokenAsset(t *testing.T) { + ctx, chaincodeStub := wtest.PrepMockStub() + sc := sa.SmartContract{} + sc.ConfigureInterop("interopcc") + + bondLocker := getLockerECertBase64() + bondRecipient := getRecipientECertBase64() + bondType := "bond" + bondId := "b01" + bondIssuer := "network1" + bondFaceValue := 1 + currentTime := time.Now() + bondMaturityDate := currentTime.Add(time.Hour * 24) // maturity date is 1 day after current time + + tokenType := "cbdc" + tokenIssuer := "network2" + tokenValue := 1 + numTokens := uint64(10) + tokensLocker := getRecipientECertBase64() + tokensRecipient := getLockerECertBase64() + + + // Create bond asset + // let ctx.GetStub().GetState() return that the bond asset didn't exist before + chaincodeStub.GetStateReturnsOnCall(0, nil, nil) + err := sc.CreateAsset(ctx, bondType, bondId, bondLocker, bondIssuer, bondFaceValue, bondMaturityDate.Format(time.RFC822)) + require.NoError(t, err) + + + // Create token asset type + chaincodeStub.GetStateReturnsOnCall(1, nil, nil) + res, err := sc.CreateTokenAssetType(ctx, tokenType, tokenIssuer, tokenValue) + require.NoError(t, err) + require.Equal(t, res, true) + + + // Issue token assets for Bob + tokenAssetType := sa.TokenAssetType { + Issuer: tokenIssuer, + Value: tokenValue, + } + tokenAssetTypeBytes, _ := json.Marshal(tokenAssetType) + chaincodeStub.GetStateReturnsOnCall(2, tokenAssetTypeBytes, nil) + walletMap := make(map[string]uint64) + tokensWallet := &sa.TokenWallet{WalletMap: walletMap} + tokensWalletBytes, _ := json.Marshal(tokensWallet) + chaincodeStub.GetStateReturnsOnCall(3, tokensWalletBytes, nil) + err = sc.IssueTokenAssets(ctx, tokenType, numTokens, getRecipientECertBase64()) + require.NoError(t, err) + + + // Lock bond asset in network1 by Alice for Bob + fmt.Println("*** Lock bond asset in network1 by Alice ***") + preimage := "abcd" + hashBase64 := generateSHA256HashInBase64Form(preimage) + defaultTimeLockSecs := uint64(300) // set default locking period as 5 minutes + currentTimeSecs := uint64(time.Now().Unix()) + bondContractId := "bond-contract" + lockInfoHTLC := &common.AssetLockHTLC { + HashBase64: []byte(hashBase64), + ExpiryTimeSecs: currentTimeSecs + defaultTimeLockSecs, + TimeSpec: common.TimeSpec_EPOCH, + } + lockInfoHTLCBytes, _ := proto.Marshal(lockInfoHTLC) + lockInfo := &common.AssetLock{ + LockInfo: lockInfoHTLCBytes, + } + lockInfoBytes, _ := proto.Marshal(lockInfo) + bondAgreement := &common.AssetExchangeAgreement { + AssetType: bondType, + Id: bondId, + Locker: bondLocker, + Recipient: bondRecipient, + } + bondAgreementBytes, _ := proto.Marshal(bondAgreement) + bondAsset := sa.BondAsset { + Type: bondType, + ID: bondId, + Owner: bondLocker, + Issuer: bondIssuer, + FaceValue: bondFaceValue, + MaturityDate: bondMaturityDate, + } + bondAssetBytes, err := json.Marshal(bondAsset) + chaincodeStub.GetCreatorReturnsOnCall(0, []byte(getCreatorInContext("locker")), nil) + chaincodeStub.GetStateReturnsOnCall(4, bondAssetBytes, nil) + chaincodeStub.InvokeChaincodeReturnsOnCall(0, shim.Success([]byte("false"))) + chaincodeStub.InvokeChaincodeReturnsOnCall(1, shim.Success([]byte(bondContractId))) + bondContractId, err = sc.LockAsset(ctx, base64.StdEncoding.EncodeToString(bondAgreementBytes), base64.StdEncoding.EncodeToString(lockInfoBytes)) + require.NoError(t, err) + require.NotEmpty(t, bondContractId) + + + // Lock token asset in network2 by Bob for Alice + fmt.Println("*** Lock token asset in network2 by Bob ***") + tokensContractId := "tokens-contract" + tokensAgreement := &common.FungibleAssetExchangeAgreement { + AssetType: tokenType, + NumUnits: numTokens, + Locker: tokensLocker, + Recipient: tokensRecipient, + } + tokensAgreementBytes, _ := proto.Marshal(tokensAgreement) + chaincodeStub.GetCreatorReturnsOnCall(1, []byte(getCreatorInContext("recipient")), nil) + tokenAssetType = sa.TokenAssetType { + Issuer: tokenIssuer, + Value: tokenValue, + } + tokenAssetTypeBytes, _ = json.Marshal(tokenAssetType) + chaincodeStub.GetStateReturnsOnCall(5, tokenAssetTypeBytes, nil) + walletMap = make(map[string]uint64) + walletMap[tokenType] = numTokens + tokensWallet = &sa.TokenWallet{WalletMap: walletMap} + tokensWalletBytes, _ = json.Marshal(tokensWallet) + chaincodeStub.GetStateReturnsOnCall(6, tokensWalletBytes, nil) + chaincodeStub.InvokeChaincodeReturnsOnCall(2, shim.Success([]byte(tokensContractId))) + chaincodeStub.GetCreatorReturnsOnCall(2, []byte(getCreatorInContext("recipient")), nil) + chaincodeStub.GetStateReturnsOnCall(7, tokenAssetTypeBytes, nil) + chaincodeStub.GetStateReturnsOnCall(8, tokensWalletBytes, nil) + tokensContractId, err = sc.LockFungibleAsset(ctx, base64.StdEncoding.EncodeToString(tokensAgreementBytes), base64.StdEncoding.EncodeToString(lockInfoBytes)) + require.NoError(t, err) + require.NotEmpty(t, tokensContractId) + + + // Claim token asset in network2 by Alice + fmt.Println("*** Claim token asset in network2 by Alice ***") + preimageBase64 := base64.StdEncoding.EncodeToString([]byte(preimage)) + claimInfoHTLC := &common.AssetClaimHTLC { + HashPreimageBase64: []byte(preimageBase64), + } + claimInfoHTLCBytes, _ := proto.Marshal(claimInfoHTLC) + claimInfo := &common.AssetClaim{ + ClaimInfo: claimInfoHTLCBytes, + LockMechanism: common.LockMechanism_HTLC, + } + claimInfoBytes, _ := proto.Marshal(claimInfo) + chaincodeStub.InvokeChaincodeReturnsOnCall(3, shim.Success(nil)) + chaincodeStub.GetCreatorReturnsOnCall(3, []byte(getCreatorInContext("locker")), nil) + chaincodeStub.GetCreatorReturnsOnCall(4, []byte(getCreatorInContext("locker")), nil) + tokenAssetType = sa.TokenAssetType { + Issuer: tokenIssuer, + Value: tokenValue, + } + tokenAssetTypeBytes, _ = json.Marshal(tokenAssetType) + contractedTokenAsset := ContractedFungibleAsset{ + Type: tokenType, + NumUnits: numTokens, + } + + contractedTokenAssetBytes, _ := json.Marshal(contractedTokenAsset) + chaincodeStub.GetStateReturnsOnCall(9, tokenAssetTypeBytes, nil) + chaincodeStub.GetStateReturnsOnCall(10, contractedTokenAssetBytes, nil) + chaincodeStub.GetStateReturnsOnCall(11, nil, nil) + _, err = sc.ClaimFungibleAsset(ctx, base64.StdEncoding.EncodeToString(tokensAgreementBytes), base64.StdEncoding.EncodeToString(claimInfoBytes)) + require.NoError(t, err) + + + // Claim bond asset in network1 by Bob + fmt.Println("*** Claim bond asset in network1 by Bob ***") + chaincodeStub.InvokeChaincodeReturnsOnCall(4, shim.Success(nil)) + chaincodeStub.InvokeChaincodeReturnsOnCall(5, shim.Success([]byte("true"))) + chaincodeStub.InvokeChaincodeReturnsOnCall(6, shim.Success([]byte("true"))) + chaincodeStub.GetCreatorReturnsOnCall(5, []byte(getCreatorInContext("recipient")), nil) + chaincodeStub.GetStateReturnsOnCall(12, bondAssetBytes, nil) + chaincodeStub.GetStateReturnsOnCall(13, []byte(bondContractId), nil) + _, err = sc.ClaimAsset(ctx, base64.StdEncoding.EncodeToString(bondAgreementBytes), base64.StdEncoding.EncodeToString(claimInfoBytes)) + require.NoError(t, err) + +} diff --git a/weaver/samples/fabric/satpsimpleasset/bondasset.go b/weaver/samples/fabric/satpsimpleasset/bondasset.go new file mode 100644 index 0000000000..e5cb7cbf1f --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/bondasset.go @@ -0,0 +1,327 @@ +package main + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "time" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/cacti/weaver/common/protos-go/v2/common" + "github.com/hyperledger/fabric-contract-api-go/contractapi" +) + + +type BondAsset struct { + Type string `json:"type"` + ID string `json:"id"` + Owner string `json:"owner"` + Issuer string `json:"issuer"` + FaceValue int `json:"facevalue"` + MaturityDate time.Time `json:"maturitydate"` +} + +func getBondAssetKey(assetType string, assetId string) string { + return assetType + assetId +} + +func getBondAsset(ctx contractapi.TransactionContextInterface, assetType, id string) (*BondAsset, error) { + assetJSON, err := ctx.GetStub().GetState(getBondAssetKey(assetType, id)) + if err != nil { + return nil, fmt.Errorf("failed to read asset record from world state: %v", err) + } + if assetJSON == nil { + return nil, fmt.Errorf("the asset %s does not exist", id) + } + + var asset BondAsset + err = json.Unmarshal(assetJSON, &asset) + if err != nil { + return nil, err + } + return &asset, nil +} + +// InitBondAssetLedger adds a base set of assets to the ledger +func (s *SmartContract) InitBondAssetLedger(ctx contractapi.TransactionContextInterface) error { + assets := []BondAsset{ + {Type: "t1", ID: "a01", Issuer: "Treasury" , Owner: "", FaceValue: 300, + MaturityDate: time.Date(2022, time.April, 1, 12, 0, 0, 0, time.UTC)}, + {Type: "t1", ID: "a02", Issuer: "Treasury" , Owner: "", FaceValue: 400, + MaturityDate: time.Date(2022, time.July, 1, 12, 0, 0, 0, time.UTC)}, + } + + for _, asset := range assets { + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + err = ctx.GetStub().PutState(getBondAssetKey(asset.Type, asset.ID), assetJSON) + if err != nil { + return fmt.Errorf("failed to put to world state. %v", err) + } + } + + return nil +} + +// CreateAsset issues a new asset to the world state with given details. +func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, assetType, id, owner, issuer string, faceValue int, maturityDate string) error { + if assetType == "" { + return fmt.Errorf("Asset type cannot be blank") + } + if id == "" { + return fmt.Errorf("Asset ID cannot be blank") + } + if owner == "" && issuer == "" { + return fmt.Errorf("Asset Owner and Issuer cannot both be blank") + } + exists, err := s.AssetExists(ctx, assetType, id) + if err != nil { + return err + } + if exists { + return fmt.Errorf("the asset %s already exists", id) + } + + md_time, err := time.Parse(time.RFC822, maturityDate) + if err != nil { + return fmt.Errorf("maturity date provided is not in correct format, please use this format: %s", time.RFC822) + } + + if md_time.Before(time.Now()) { + return fmt.Errorf("maturity date can not be in past.") + } + + asset := BondAsset{ + Type: assetType, + ID: id, + Owner: owner, + Issuer: issuer, + FaceValue: faceValue, + MaturityDate: md_time, + } + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// ReadAsset returns the asset stored in the world state with given id. +// This function is called with the parameter inUpdateOwnerContext value as false, except in the update-owner context +func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, assetType, id string) (*BondAsset, error) { + asset, err := getBondAsset(ctx, assetType, id) + if err != nil { + return nil, err + } + if !checkAccessToAsset(s, ctx, asset) { + return nil, fmt.Errorf("cannot access Bond Asset %s", id) + } + return asset, nil +} + +// DeleteAsset deletes an given asset from the world state. +func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, assetType, id string) error { + + // Read the asset (which internally check access) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + return ctx.GetStub().DelState(getBondAssetKey(asset.Type, asset.ID)) +} + + +// isCallerAssetOwner returns true only if the invoker of the transaction is also the asset owner +func isCallerAssetOwner(ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + caller, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + fmt.Println(err.Error()) + return false + } + return (asset.Owner == caller) +} + +// isBondAssetLocked returns true only if the asset is presently locked +func isBondAssetLocked(s *SmartContract, ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + bondAssetAgreement := &common.AssetExchangeAgreement{ + AssetType: asset.Type, + Id: asset.ID, + Recipient: "*", + Locker: asset.Owner, + } + bondAssetAgreementProtoSerialized, err := proto.Marshal(bondAssetAgreement) + if err != nil { + fmt.Println(err.Error()) + return false + } + bondAssetAgreementProto64 := base64.StdEncoding.EncodeToString(bondAssetAgreementProtoSerialized) + locked, err := s.IsAssetLocked(ctx, bondAssetAgreementProto64) + if err != nil { + fmt.Println(err.Error()) + return false + } + return locked +} + +// isBondAssetLockedForMe returns true only if the asset is presently locked for me +func isBondAssetLockedForMe(s *SmartContract, ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + bondAssetAgreement := &common.AssetExchangeAgreement{ + AssetType: asset.Type, + Id: asset.ID, + Recipient: "", + Locker: asset.Owner, + } + bondAssetAgreementProtoSerialized, err := proto.Marshal(bondAssetAgreement) + if err != nil { + fmt.Println(err.Error()) + return false + } + bondAssetAgreementProto64 := base64.StdEncoding.EncodeToString(bondAssetAgreementProtoSerialized) + locked, err := s.IsAssetLocked(ctx, bondAssetAgreementProto64) + if err != nil { + fmt.Println(err.Error()) + return false + } + return locked +} + +// checkAccessToAsset checks several conditions under which an asset can be put on hold (i.e., not available for regular business operation) +func checkAccessToAsset(s *SmartContract, ctx contractapi.TransactionContextInterface, asset *BondAsset) bool { + // Ensure that the client is the owner of the asset + if !isCallerAssetOwner(ctx, asset) { + fmt.Printf("Illegal update: caller is not owner of asset %s\n", asset.ID) + return false + } + + // Ensure that the asset is not locked + if isBondAssetLocked(s, ctx, asset) { + fmt.Printf("Cannot update attributes of locked asset %s\n", asset.ID) + return false + } + + return true +} + +// AssetExists returns true when asset with given ID exists in world state +func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, assetType, id string) (bool, error) { + assetJSON, err := ctx.GetStub().GetState(getBondAssetKey(assetType, id)) + if err != nil { + return false, fmt.Errorf("failed to read asset record from world state: %v", err) + } + + return assetJSON != nil, nil +} + +// IsAssetReleased returns true if asset maturity date elapses +func (s *SmartContract) IsAssetReleased(ctx contractapi.TransactionContextInterface, assetType, id string) (bool, error) { + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return false, err + } + currDate := time.Now() + if (currDate.After(asset.MaturityDate)) { + return true, nil + } + + return false, nil +} + +// UpdateOwner sets the owner of an asset to a new owner. +func (s *SmartContract) UpdateOwner(ctx contractapi.TransactionContextInterface, assetType, id string, newOwner string) error { + // Read asset (which internally checks access if it is free to modified) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + + asset.Owner = newOwner + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// UpdateMaturityDate sets the maturity date of the asset to an updated date as passed in the parameters. +func (s *SmartContract) UpdateMaturityDate(ctx contractapi.TransactionContextInterface, assetType, id string, newMaturityDate time.Time) error { + // Read asset (which internally checks access if it is free to modified) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + + asset.MaturityDate = newMaturityDate + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// UpdateFaceValue sets the face value of an asset to the new value passed. +func (s *SmartContract) UpdateFaceValue(ctx contractapi.TransactionContextInterface, assetType, id string, newFaceValue int) error { + // Read asset (which internally checks access if it is free to modified) + asset, err := s.ReadAsset(ctx, assetType, id) + if err != nil { + return err + } + + asset.FaceValue = newFaceValue + assetJSON, err := json.Marshal(asset) + if err != nil { + return err + } + + return ctx.GetStub().PutState(getBondAssetKey(assetType, id), assetJSON) +} + +// GetMyAssets returns the assets owner by the caller +func (s *SmartContract) GetMyAssets(ctx contractapi.TransactionContextInterface) ([]*BondAsset, error) { + assets, err := s.GetAllAssets(ctx) + if err != nil { + return nil, err + } + + var myassets []*BondAsset + + for _, asset := range assets { + if checkAccessToAsset(s, ctx, asset) { + myassets = append(myassets, asset) + } + } + return myassets, nil +} + +// GetAllAssets returns all assets found in world state +func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*BondAsset, error) { + // range query with empty string for startKey and endKey does an + // open-ended query of all assets in the chaincode namespace. + resultsIterator, err := ctx.GetStub().GetStateByRange("", "") + if err != nil { + return nil, err + } + defer resultsIterator.Close() + + var assets []*BondAsset + for resultsIterator.HasNext() { + queryResponse, err := resultsIterator.Next() + if err != nil { + return nil, err + } + + var asset BondAsset + err = json.Unmarshal(queryResponse.Value, &asset) + if err != nil { + return nil, err + } + assets = append(assets, &asset) + } + + return assets, nil +} diff --git a/weaver/samples/fabric/satpsimpleasset/bondasset_test.go b/weaver/samples/fabric/satpsimpleasset/bondasset_test.go new file mode 100644 index 0000000000..b43170e23a --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/bondasset_test.go @@ -0,0 +1,242 @@ +package main_test + +import ( + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/hyperledger/fabric-protos-go/ledger/queryresult" + sa "github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset" + "github.com/stretchr/testify/require" + wtest "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils" + wtestmocks "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils/mocks" +) + +const ( + defaultAssetType = "BearerBonds" + defaultAssetId = "asset1" + defaultAssetOwner = "Alice" + defaultAssetIssuer = "Treasury" +) + +func TestInitBondAssetLedger(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + err := simpleAsset.InitBondAssetLedger(transactionContext) + require.NoError(t, err) + + chaincodeStub.PutStateReturns(fmt.Errorf("failed inserting key")) + err = simpleAsset.InitBondAssetLedger(transactionContext) + require.EqualError(t, err, "failed to put to world state. failed inserting key") +} + +func TestCreateAsset(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + err := simpleAsset.CreateAsset(transactionContext, "", "", "", "", 0, "02 Jan 26 15:04 MST") + require.Error(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, "", "", "", 0, "02 Jan 26 15:04 MST") + require.Error(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, "", "", 0, "02 Jan 26 15:04 MST") + require.Error(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "02 Jan 26 15:04 MST") + require.NoError(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, "", defaultAssetIssuer, 0, "02 Jan 26 15:04 MST") + require.NoError(t, err) + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "02 Jan 06 15:04 MST") + require.EqualError(t, err, "maturity date can not be in past.") + + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "") + require.EqualError(t, err, "maturity date provided is not in correct format, please use this format: 02 Jan 06 15:04 MST") + + chaincodeStub.GetStateReturns([]byte{}, nil) + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "") + require.EqualError(t, err, "the asset asset1 already exists") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.CreateAsset(transactionContext, defaultAssetType, defaultAssetId, defaultAssetOwner, "", 0, "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestReadAsset(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + expectedAsset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + asset, err := simpleAsset.ReadAsset(transactionContext, "", "") + require.NoError(t, err) + require.Equal(t, expectedAsset, asset) + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + _, err = simpleAsset.ReadAsset(transactionContext, "", "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") + + chaincodeStub.GetStateReturns(nil, nil) + asset, err = simpleAsset.ReadAsset(transactionContext, "", "asset1") + require.EqualError(t, err, "the asset asset1 does not exist") + require.Nil(t, asset) +} + +func TestUpdateFaceValue(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + expectedAsset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleAsset.UpdateFaceValue(transactionContext, "", "", 0) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, nil) + err = simpleAsset.UpdateFaceValue(transactionContext, "", "asset1", 0) + require.EqualError(t, err, "the asset asset1 does not exist") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.UpdateFaceValue(transactionContext, "", "asset1", 0) + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestUpdateMaturityDate(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + expectedAsset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleAsset.UpdateMaturityDate(transactionContext, "", "", time.Now()) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, nil) + err = simpleAsset.UpdateMaturityDate(transactionContext, "", "asset1", time.Now()) + require.EqualError(t, err, "the asset asset1 does not exist") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.UpdateMaturityDate(transactionContext, "", "asset1", time.Now()) + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestDeleteAsset(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + asset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(nil) + err = simpleAsset.DeleteAsset(transactionContext, "", "") + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, nil) + err = simpleAsset.DeleteAsset(transactionContext, "", "asset1") + require.EqualError(t, err, "the asset asset1 does not exist") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.DeleteAsset(transactionContext, "", "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestUpdateOwner(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + + asset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleAsset.UpdateOwner(transactionContext, "", "", "") + require.NoError(t, err) + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + err = simpleAsset.UpdateOwner(transactionContext, "", "", "") + require.EqualError(t, err, "failed to read asset record from world state: unable to retrieve asset") +} + +func TestGetMyAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + iterator := &wtestmocks.StateQueryIterator{} + + asset := &sa.BondAsset{ID: "asset1", Owner: getTestTxCreatorECertBase64()} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + iterator.HasNextReturnsOnCall(0, true) + iterator.HasNextReturnsOnCall(1, false) + iterator.NextReturns(&queryresult.KV{Value: bytes}, nil) + + chaincodeStub.GetCreatorReturns([]byte(getCreator()), nil) + + chaincodeStub.GetStateByRangeReturns(iterator, nil) + assets, err := simpleAsset.GetAllAssets(transactionContext) + require.NoError(t, err) + require.Equal(t, []*sa.BondAsset{asset}, assets) + + iterator.HasNextReturns(true) + iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving next item") + require.Nil(t, assets) + + chaincodeStub.GetStateByRangeReturns(nil, fmt.Errorf("failed retrieving all assets")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving all assets") + require.Nil(t, assets) +} + +func TestGetAllAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleAsset := sa.SmartContract{} + simpleAsset.ConfigureInterop("interopcc") + iterator := &wtestmocks.StateQueryIterator{} + + asset := &sa.BondAsset{ID: "asset1"} + bytes, err := json.Marshal(asset) + require.NoError(t, err) + + iterator.HasNextReturnsOnCall(0, true) + iterator.HasNextReturnsOnCall(1, false) + iterator.NextReturns(&queryresult.KV{Value: bytes}, nil) + + chaincodeStub.GetStateByRangeReturns(iterator, nil) + assets, err := simpleAsset.GetAllAssets(transactionContext) + require.NoError(t, err) + require.Equal(t, []*sa.BondAsset{asset}, assets) + + iterator.HasNextReturns(true) + iterator.NextReturns(nil, fmt.Errorf("failed retrieving next item")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving next item") + require.Nil(t, assets) + + chaincodeStub.GetStateByRangeReturns(nil, fmt.Errorf("failed retrieving all assets")) + assets, err = simpleAsset.GetAllAssets(transactionContext) + require.EqualError(t, err, "failed retrieving all assets") + require.Nil(t, assets) +} diff --git a/weaver/samples/fabric/satpsimpleasset/go.mod b/weaver/samples/fabric/satpsimpleasset/go.mod new file mode 100644 index 0000000000..eedb9f8ddb --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/go.mod @@ -0,0 +1,42 @@ +module github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset + +go 1.20 + +require ( + github.com/golang/protobuf v1.5.3 + github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 + github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 + github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils v0.0.0-20230907062207-cd6eb2f89fb4 + github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a + github.com/hyperledger/fabric-contract-api-go v1.2.1 + github.com/hyperledger/fabric-protos-go v0.3.0 + github.com/sirupsen/logrus v1.9.0 + github.com/stretchr/testify v1.8.2 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/spec v0.20.8 // indirect + github.com/go-openapi/swag v0.21.1 // indirect + github.com/gobuffalo/envy v1.10.1 // indirect + github.com/gobuffalo/packd v1.0.1 // indirect + github.com/gobuffalo/packr v1.30.1 // indirect + github.com/joho/godotenv v1.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rogpeppe/go-internal v1.8.1 // indirect + 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.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect + google.golang.org/grpc v1.54.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/weaver/samples/fabric/satpsimpleasset/go.sum b/weaver/samples/fabric/satpsimpleasset/go.sum new file mode 100644 index 0000000000..da4c985ffd --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/go.sum @@ -0,0 +1,149 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU= +github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.10.1 h1:ppDLoXv2feQ5nus4IcgtyMdHQkKng2lhJCIm33cblM0= +github.com/gobuffalo/envy v1.10.1/go.mod h1:AWx4++KnNOW3JOeEvhSaq+mvgAvnMYOY1XSIin4Mago= +github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= +github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY= +github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= +github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= +github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a h1:HwSCxEeiBthwcazcAykGATQ36oG9M+HEQvGLvB7aLvA= +github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a/go.mod h1:TDSu9gxURldEnaGSFbH1eMlfSQBWQcMQfnDBcpQv5lU= +github.com/hyperledger/fabric-contract-api-go v1.2.1 h1:Ww9cKH/qHl5s6WqF+Ts5ju5eaBxC/awB/BJE+rOsEkM= +github.com/hyperledger/fabric-contract-api-go v1.2.1/go.mod h1:BhWve0gz1iH+Xc+cO3rmeIZI7YaTWOQodka9CgeUOgo= +github.com/hyperledger/fabric-protos-go v0.3.0 h1:MXxy44WTMENOh5TI8+PCK2x6pMj47Go2vFRKDHB2PZs= +github.com/hyperledger/fabric-protos-go v0.3.0/go.mod h1:WWnyWP40P2roPmmvxsUXSvVI/CF6vwY1K1UFidnKBys= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +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/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.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +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.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +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 v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +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-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/weaver/samples/fabric/satpsimpleasset/helper.go b/weaver/samples/fabric/satpsimpleasset/helper.go new file mode 100644 index 0000000000..efca833cc7 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/helper.go @@ -0,0 +1,53 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// helper contains miscelaneous helper functions used throughout the code +package main + +import ( + "fmt" + "errors" + "encoding/base64" + "bytes" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric-contract-api-go/contractapi" + mspProtobuf "github.com/hyperledger/fabric-protos-go/msp" + log "github.com/sirupsen/logrus" +) + +// functions to log and return errors +func logThenErrorf(format string, args ...interface{}) error { + errorMsg := fmt.Sprintf(format, args...) + log.Error(errorMsg) + return errors.New(errorMsg) +} + +func getECertOfTxCreatorBase64(ctx contractapi.TransactionContextInterface) (string, error) { + + txCreatorBytes, err := ctx.GetStub().GetCreator() + if err != nil { + return "", fmt.Errorf("unable to get the transaction creator information: %+v", err) + } + + serializedIdentity := &mspProtobuf.SerializedIdentity{} + err = proto.Unmarshal(txCreatorBytes, serializedIdentity) + if err != nil { + return "", fmt.Errorf("getECertOfTxCreatorBase64: unmarshal error: %+v", err) + } + + eCertBytesBase64 := base64.StdEncoding.EncodeToString(serializedIdentity.IdBytes) + + return eCertBytesBase64, nil +} + +func createKeyValuePairs(m map[string]uint64) string { + b := new(bytes.Buffer) + for key, value := range m { + fmt.Fprintf(b, "%s=\"%d\"\n", key, value) + } + return b.String() +} diff --git a/weaver/samples/fabric/satpsimpleasset/main.go b/weaver/samples/fabric/satpsimpleasset/main.go new file mode 100644 index 0000000000..0b8c5b9d71 --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/main.go @@ -0,0 +1,59 @@ +package main + +import ( + "fmt" + "os" + + "github.com/hyperledger/fabric-chaincode-go/shim" + "github.com/hyperledger/fabric-contract-api-go/contractapi" + am "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2" +) + +// SmartContract provides functions for managing an BondAsset and TokenAsset +type SmartContract struct { + contractapi.Contract + amc am.AssetManagementContract +} + +func (s *SmartContract) ConfigureInterop(interopChaincodeId string) { + s.amc.Configure(interopChaincodeId) +} + +func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface, ccType string, interopChaincodeId string) error { + s.ConfigureInterop(interopChaincodeId) + if ccType == "Bond" { + return s.InitBondAssetLedger(ctx) + } else if ccType == "Token" { + return s.InitTokenAssetLedger(ctx) + } + return fmt.Errorf("only Bond and Token are accepted as ccType.") +} + +func main() { + chaincode, err := contractapi.NewChaincode(new(SmartContract)) + + if err != nil { + fmt.Printf("Error creating chaincode: %s", err.Error()) + return + } + + _, ok := os.LookupEnv("EXTERNAL_SERVICE") + if ok { + server := &shim.ChaincodeServer{ + CCID: os.Getenv("CHAINCODE_CCID"), + Address: os.Getenv("CHAINCODE_ADDRESS"), + CC: chaincode, + TLSProps: shim.TLSProperties{ + Disabled: true, + }, + } + // Start the chaincode external server + err = server.Start() + } else { + err = chaincode.Start() + } + if err != nil { + fmt.Printf("Error starting chaincode: %s", err.Error()) + } + +} diff --git a/weaver/samples/fabric/satpsimpleasset/tokenasset.go b/weaver/samples/fabric/satpsimpleasset/tokenasset.go new file mode 100644 index 0000000000..972d90399a --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/tokenasset.go @@ -0,0 +1,316 @@ +package main + +import ( + "encoding/json" + "fmt" + + "github.com/hyperledger/fabric-contract-api-go/contractapi" +) + +type TokenAssetType struct { + Issuer string `json:"issuer"` + Value int `json:"value"` +} +type TokenWallet struct { + WalletMap map[string]uint64 `json:"walletlist"` +} + + +// InitTokenAssetLedger adds a base set of assets to the ledger +func (s *SmartContract) InitTokenAssetLedger(ctx contractapi.TransactionContextInterface) error { + _, err := s.CreateTokenAssetType(ctx, "token1", "CentralBank", 1) + if err != nil { + return err + } + return err +} + +// CreateTokenAssetType issues a new token asset type to the world state with given details. +func (s *SmartContract) CreateTokenAssetType(ctx contractapi.TransactionContextInterface, tokenAssetType string, issuer string, value int) (bool, error) { + if tokenAssetType == "" { + return false, fmt.Errorf("Token asset type cannot be blank") + } + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return false, err + } + if exists { + return false, fmt.Errorf("the token asset type %s already exists.", tokenAssetType) + } + + asset := TokenAssetType{ + Issuer: issuer, + Value: value, + } + assetJSON, err := json.Marshal(asset) + if err != nil { + return false, err + } + id := getTokenAssetTypeId(tokenAssetType) + err = ctx.GetStub().PutState(id, assetJSON) + + if err != nil { + return false, fmt.Errorf("failed to create token asset type %s. %v", tokenAssetType, err) + } + return true, nil +} + +// ReadTokenAssetType returns the token asset type stored in the world state with given type. +func (s *SmartContract) ReadTokenAssetType(ctx contractapi.TransactionContextInterface, tokenAssetType string) (*TokenAssetType, error) { + id := getTokenAssetTypeId(tokenAssetType) + assetJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return nil, fmt.Errorf("failed to read token asset type %s: %v", tokenAssetType, err) + } + if assetJSON == nil { + return nil, fmt.Errorf("the token asset type %s does not exist.", tokenAssetType) + } + + var fat TokenAssetType + err = json.Unmarshal(assetJSON, &fat) + if err != nil { + return nil, err + } + + return &fat, nil +} + +// DeleteTokenAssetType deletes an given token asset type from the world state. +func (s *SmartContract) DeleteTokenAssetType(ctx contractapi.TransactionContextInterface, tokenAssetType string) error { + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the token asset type %s does not exist.", tokenAssetType) + } + + id := getTokenAssetTypeId(tokenAssetType) + err = ctx.GetStub().DelState(id) + if err != nil { + return fmt.Errorf("failed to delete token asset type %s: %v", tokenAssetType, err) + } + return nil +} + +// TokenAssetTypeExists returns true when token asset type with given ID exists in world state +func (s *SmartContract) TokenAssetTypeExists(ctx contractapi.TransactionContextInterface, tokenAssetType string) (bool, error) { + id := getTokenAssetTypeId(tokenAssetType) + assetJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return false, fmt.Errorf("failed to read from world state: %v", err) + } + + return assetJSON != nil, nil +} + +// IssueTokenAssets issues new token assets to an owner. +func (s *SmartContract) IssueTokenAssets(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, owner string) error { + if owner == "" { + return fmt.Errorf("Owner cannot be blank") + } + + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("cannot issue: the token asset type %s does not exist", tokenAssetType) + } + + id := getWalletId(owner) + return addTokenAssetsHelper(ctx, tokenAssetType, numUnits, id) +} + +// DeleteTokenAssets burns the token assets from an owner. +func (s *SmartContract) DeleteTokenAssets(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64) error { + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return err + } + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the token asset type %s does not exist", tokenAssetType) + } + + id := getWalletId(owner) + return subTokenAssetsHelper(ctx, tokenAssetType, numUnits, id) +} + +// TransferTokenAssets transfers the token assets from client's account to newOwner +func (s *SmartContract) TransferTokenAssets(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, newOwner string) error { + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the token asset type %s does not exist", tokenAssetType) + } + + if newOwner == "" { + return fmt.Errorf("New owner cannot be blank") + } + + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return err + } + + ownerId := getWalletId(owner) + newOwnerId := getWalletId(newOwner) + + err = subTokenAssetsHelper(ctx, tokenAssetType, numUnits, ownerId) + if err != nil { + return err + } + return addTokenAssetsHelper(ctx, tokenAssetType, numUnits, newOwnerId) +} + +// GetBalance returns the amount of given token asset type owned by an owner. +func (s *SmartContract) GetBalance(ctx contractapi.TransactionContextInterface, tokenAssetType string, owner string) (uint64, error) { + exists, err := s.TokenAssetTypeExists(ctx, tokenAssetType) + if err != nil { + return 0, err + } + if !exists { + return 0, fmt.Errorf("the token asset type %s does not exist", tokenAssetType) + } + + id := getWalletId(owner) + walletJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return 0, fmt.Errorf("failed to read owner's wallet from world state: %v", err) + } + if walletJSON == nil { + return 0, fmt.Errorf("owner does not have a wallet") + } + + var wallet TokenWallet + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return 0, err + } + balance := wallet.WalletMap[tokenAssetType] + return balance, nil +} + +// GetMyWallet returns the available amount for each token asset type owned by an owner. +func (s *SmartContract) GetMyWallet(ctx contractapi.TransactionContextInterface) (string, error) { + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return "", err + } + + id := getWalletId(owner) + walletJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return "", fmt.Errorf("failed to read owner's wallet from world state: %v", err) + } + if walletJSON == nil { + return "", fmt.Errorf("owner does not have a wallet") + } + + var wallet TokenWallet + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return "", err + } + return createKeyValuePairs(wallet.WalletMap), nil +} + +// Checks if owner has some given amount of token asset +func (s *SmartContract) TokenAssetsExist(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64) (bool, error) { + owner, err := getECertOfTxCreatorBase64(ctx) + if err != nil { + return false, err + } + balance, err := s.GetBalance(ctx, tokenAssetType, owner) + if err != nil { + return false, err + } + return balance >= numUnits, nil +} + +// Helper Functions for token asset +func addTokenAssetsHelper(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, id string) error { + walletJSON, err := ctx.GetStub().GetState(id) + if err != nil { + return logThenErrorf("failed to retrieve entry from ledger: %+v", err) + } + var wallet TokenWallet + if walletJSON != nil { + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return err + } + balance := wallet.WalletMap[tokenAssetType] + wallet.WalletMap[tokenAssetType] = balance + numUnits + } else { + walletMap := make(map[string]uint64) + walletMap[tokenAssetType] = numUnits + wallet = TokenWallet{ + WalletMap: walletMap, + } + } + + walletNewJSON, err := json.Marshal(wallet) + if err != nil { + return err + } + return ctx.GetStub().PutState(id, walletNewJSON) +} + +func subTokenAssetsHelper(ctx contractapi.TransactionContextInterface, tokenAssetType string, numUnits uint64, id string) error { + walletJSON, err := ctx.GetStub().GetState(id) + var wallet TokenWallet + if err != nil { + return err + } + if walletJSON == nil { + return fmt.Errorf("owner does not have a wallet") + } + + err = json.Unmarshal(walletJSON, &wallet) + if err != nil { + return err + } + + // Check if owner has sufficient amount of given type to delete + _, exists := wallet.WalletMap[tokenAssetType] + if !exists { + return fmt.Errorf("the owner does not possess any units of the token asset type %s", tokenAssetType) + } + if wallet.WalletMap[tokenAssetType] < numUnits { + return fmt.Errorf("the owner does not possess enough units of the token asset type %s", tokenAssetType) + } + + // Subtract after all checks + wallet.WalletMap[tokenAssetType] -= numUnits + + // Delete token asset type from map if num of units becomes zero + if wallet.WalletMap[tokenAssetType] == 0 { + delete(wallet.WalletMap, tokenAssetType) + } + + if len(wallet.WalletMap) == 0 { + // Delete the entry from State if wallet becomes empty + return ctx.GetStub().DelState(id) + } else { + // Update the new wallet object otherwise + walletNewJSON, err := json.Marshal(wallet) + if err != nil { + return err + } + return ctx.GetStub().PutState(id, walletNewJSON) + } +} + +func getTokenAssetTypeId(tokenAssetType string) string { + return "FAT_" + tokenAssetType +} +func getWalletId(owner string) string { + return "W_" + owner +} diff --git a/weaver/samples/fabric/satpsimpleasset/tokenasset_test.go b/weaver/samples/fabric/satpsimpleasset/tokenasset_test.go new file mode 100644 index 0000000000..facbfb393f --- /dev/null +++ b/weaver/samples/fabric/satpsimpleasset/tokenasset_test.go @@ -0,0 +1,326 @@ +package main_test + +import ( + "encoding/json" + "fmt" + "testing" + "encoding/base64" + "bytes" + + "github.com/golang/protobuf/proto" + mspProtobuf "github.com/hyperledger/fabric-protos-go/msp" + sa "github.com/hyperledger/cacti/weaver/samples/fabric/satpsimpleasset" + "github.com/stretchr/testify/require" + wtest "github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils" +) + +func TestInitTokenAssetLedger(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + err := simpleToken.InitTokenAssetLedger(transactionContext) + require.NoError(t, err) + + chaincodeStub.PutStateReturns(fmt.Errorf("failed inserting key")) + err = simpleToken.InitTokenAssetLedger(transactionContext) + require.EqualError(t, err, "failed to create token asset type token1. failed inserting key") +} + +func TestCreateTokenAssetType(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + // Should fail if token asset type is empty + res, err := simpleToken.CreateTokenAssetType(transactionContext, "", "", 0) + require.Error(t, err) + + // Successful Case + res, err = simpleToken.CreateTokenAssetType(transactionContext, "sometokentype", "", 0) + require.NoError(t, err) + require.Equal(t, res, true) + + // Check if tokenAssetType already exists + chaincodeStub.GetStateReturns([]byte{}, nil) + res, err = simpleToken.CreateTokenAssetType(transactionContext, "token1", "", 0) + require.EqualError(t, err, "the token asset type token1 already exists.") + require.Equal(t, res, false) + + // Check if PutState fails + chaincodeStub.GetStateReturns(nil, nil) + chaincodeStub.PutStateReturns(fmt.Errorf("failed to put state")) + res, err = simpleToken.CreateTokenAssetType(transactionContext, "token1", "", 0) + require.EqualError(t, err, "failed to create token asset type token1. failed to put state") + require.Equal(t, res, false) + + // Check if GetState fails + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + res, err = simpleToken.CreateTokenAssetType(transactionContext, "token1", "", 0) + require.EqualError(t, err, "failed to read from world state: unable to retrieve asset") + require.Equal(t, res, false) +} + +func TestReadTokenAssetType(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + expectedAsset := &sa.TokenAssetType{Issuer: "CentralBank", Value: 10} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Successful Read + chaincodeStub.GetStateReturns(bytes, nil) + asset, err := simpleToken.ReadTokenAssetType(transactionContext, "") + require.NoError(t, err) + require.Equal(t, expectedAsset, asset) + + // GetState Fail case + chaincodeStub.GetStateReturns(nil, fmt.Errorf("unable to retrieve asset")) + _, err = simpleToken.ReadTokenAssetType(transactionContext, "") + require.EqualError(t, err, "failed to read token asset type : unable to retrieve asset") + + // token asset type does not exist + chaincodeStub.GetStateReturns(nil, nil) + asset, err = simpleToken.ReadTokenAssetType(transactionContext, "token1") + require.EqualError(t, err, "the token asset type token1 does not exist.") + require.Nil(t, asset) +} + +func TestDeleteTokenAssetType(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + chaincodeStub.DelStateReturns(nil) + err := simpleToken.DeleteTokenAssetType(transactionContext, "") + require.EqualError(t, err, "the token asset type does not exist.") + + bytes, err := json.Marshal(true) + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(fmt.Errorf("unable to retrieve asset")) + err = simpleToken.DeleteTokenAssetType(transactionContext, "token1") + require.EqualError(t, err, "failed to delete token asset type token1: unable to retrieve asset") + + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(nil) + err = simpleToken.DeleteTokenAssetType(transactionContext, "token1") + require.NoError(t, err) +} + +func TestIssueTokenAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Should fail of owner is blank + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "") + require.Error(t, err) + + // Checking succesful case + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "someowner") + require.NoError(t, err) + + // Check if writing state after issuing fails + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.PutStateReturns(fmt.Errorf("failed to put state")) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "someowner") + require.EqualError(t, err, "failed to put state") + + // Error check + chaincodeStub.GetStateReturns(nil, fmt.Errorf("failed to read state")) + err = simpleToken.IssueTokenAssets(transactionContext, "", 0, "someowner") + require.EqualError(t, err, "failed to read from world state: failed to read state") + + // Check if given token asset type doesn't exist + chaincodeStub.GetStateReturns(nil, nil) + err = simpleToken.IssueTokenAssets(transactionContext, "token1", 0, "someowner") + require.EqualError(t, err, "cannot issue: the token asset type token1 does not exist") +} + +func TestDeleteTokenAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Successful delete case + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.DeleteTokenAssets(transactionContext, "token1", 2) + require.NoError(t, err) + + // Trying to delete more than owner hass + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.DeleteTokenAssets(transactionContext, "token1", 10) + require.EqualError(t, err, "the owner does not possess enough units of the token asset type token1") + + // Trying to delete token that owner doesn't possess + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.DeleteTokenAssets(transactionContext, "token2", 2) + require.EqualError(t, err, "the owner does not possess any units of the token asset type token2") + + // Error Check + chaincodeStub.GetStateReturns(nil, fmt.Errorf("Failed to read state")) + err = simpleToken.DeleteTokenAssets(transactionContext, "", 0) + require.EqualError(t, err, "failed to read from world state: Failed to read state") + + // check if it tries to delete wallet entry when wallet list is empty + chaincodeStub.GetStateReturns(bytes, nil) + chaincodeStub.DelStateReturns(fmt.Errorf("Failed to delete state")) + err = simpleToken.DeleteTokenAssets(transactionContext, "token1", 5) + require.EqualError(t, err, "Failed to delete state") + +} +func TestTransferTokenAssets(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.TransferTokenAssets(transactionContext, "token1", 2, "") + require.Error(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.TransferTokenAssets(transactionContext, "token1", 2, "newowner") + require.NoError(t, err) + + chaincodeStub.GetStateReturns(bytes, nil) + err = simpleToken.TransferTokenAssets(transactionContext, "token1", 10, "newowner") + require.EqualError(t, err, "the owner does not possess enough units of the token asset type token1") + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("Failed to read state")) + err = simpleToken.DeleteTokenAssets(transactionContext, "", 0) + require.EqualError(t, err, "failed to read from world state: Failed to read state") +} +func TestGetBalance(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Successful GetBalance case + chaincodeStub.GetStateReturnsOnCall(0, bytes, nil) + chaincodeStub.GetStateReturnsOnCall(1, bytes, nil) + bal, err := simpleToken.GetBalance(transactionContext, "token1", "") + require.NoError(t, err) + require.Equal(t, bal, uint64(5)) + + // GetState Fails + chaincodeStub.GetStateReturnsOnCall(2, nil, fmt.Errorf("Failed to read state")) + bal, err = simpleToken.GetBalance(transactionContext, "", "") + require.EqualError(t, err, "failed to read from world state: Failed to read state") + + chaincodeStub.GetStateReturnsOnCall(3, bytes, nil) + chaincodeStub.GetStateReturnsOnCall(4, nil, fmt.Errorf("Failed to read state")) + bal, err = simpleToken.GetBalance(transactionContext, "", "") + require.EqualError(t, err, "failed to read owner's wallet from world state: Failed to read state") +} + +func TestGetMyWallet(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedRes := createKeyValuePairs(walletMap) + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + chaincodeStub.GetCreatorReturns([]byte(getCreator()), nil) + + // Successful GetBalance case + chaincodeStub.GetStateReturnsOnCall(0, bytes, nil) + bal, err := simpleToken.GetMyWallet(transactionContext) + require.NoError(t, err) + require.Equal(t, bal, expectedRes) + + chaincodeStub.GetStateReturnsOnCall(1, nil, fmt.Errorf("Failed to read state")) + bal, err = simpleToken.GetMyWallet(transactionContext) + require.EqualError(t, err, "failed to read owner's wallet from world state: Failed to read state") + + // Owner doesn't have a wallet + chaincodeStub.GetStateReturnsOnCall(2, nil, nil) + bal, err = simpleToken.GetMyWallet(transactionContext) + require.EqualError(t, err, "owner does not have a wallet") +} + +func TestTokenAssetsExist(t *testing.T) { + transactionContext, chaincodeStub := wtest.PrepMockStub() + simpleToken := sa.SmartContract{} + simpleToken.ConfigureInterop("interopcc") + + walletMap := make(map[string]uint64) + walletMap["token1"] = 5 + expectedAsset := &sa.TokenWallet{WalletMap: walletMap} + bytes, err := json.Marshal(expectedAsset) + require.NoError(t, err) + + // Token Assets exist case + chaincodeStub.GetStateReturns(bytes, nil) + res, err := simpleToken.TokenAssetsExist(transactionContext, "token1", 4) + require.NoError(t, err) + require.Equal(t, res, true) + + // Token Assets doesn't exist case + chaincodeStub.GetStateReturns(bytes, nil) + res, err = simpleToken.TokenAssetsExist(transactionContext, "token1", 6) + require.NoError(t, err) + require.Equal(t, res, false) + + chaincodeStub.GetStateReturns(nil, fmt.Errorf("Failed to read state")) + res, err = simpleToken.TokenAssetsExist(transactionContext, "", 0) + require.EqualError(t, err, "failed to read from world state: Failed to read state") + require.Equal(t, res, false) +} + +// function that supplies value that is to be returned by ctx.GetStub().GetCreator() +func getCreator() string { + serializedIdentity := &mspProtobuf.SerializedIdentity{} + eCertBytes, _ := base64.StdEncoding.DecodeString(getTestTxCreatorECertBase64()) + serializedIdentity.IdBytes = []byte(eCertBytes) + serializedIdentity.Mspid = "ca.org1.example.com" + serializedIdentityBytes, _ := proto.Marshal(serializedIdentity) + + return string(serializedIdentityBytes) +} + +// function that supplies the ECert in base64 for the transaction creator +func getTestTxCreatorECertBase64() string { + eCertBase64 := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNVVENDQWZpZ0F3SUJBZ0lSQU5qaWdnVHRhSERGRmtIaUI3VnhPN013Q2dZSUtvWkl6ajBFQXdJd2N6RUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdUQ2tOaGJHbG1iM0p1YVdFeEZqQVVCZ05WQkFjVERWTmhiaUJHY21GdVkybHpZMjh4R1RBWEJnTlZCQW9URUc5eVp6RXVaWGhoYlhCc1pTNWpiMjB4SERBYUJnTlZCQU1URTJOaExtOXlaekV1WlhoaGJYQnNaUzVqYjIwd0hoY05NVGt3TkRBeE1EZzBOVEF3V2hjTk1qa3dNekk1TURnME5UQXdXakJ6TVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNCTUtRMkZzYVdadmNtNXBZVEVXTUJRR0ExVUVCeE1OVTJGdUlFWnlZVzVqYVhOamJ6RVpNQmNHQTFVRUNoTVFiM0puTVM1bGVHRnRjR3hsTG1OdmJURWNNQm9HQTFVRUF4TVRZMkV1YjNKbk1TNWxlR0Z0Y0d4bExtTnZiVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCT2VlYTRCNlM5ZTlyLzZUWGZFZUFmZ3FrNVdpcHZZaEdveGg1ZEZuK1g0bTN2UXZTQlhuVFdLVzczZVNnS0lzUHc5dExDVytwZW9yVnMxMWdieXdiY0dqYlRCck1BNEdBMVVkRHdFQi93UUVBd0lCcGpBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFnWUlLd1lCQlFVSEF3RXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QXBCZ05WSFE0RUlnUWcxYzJHZmJTa3hUWkxIM2VzUFd3c2llVkU1QWhZNHNPQjVGOGEvaHM5WjhVd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ1JkZ1krNW9iMDNqVjJLSzFWdjZiZE5xM2NLWHc0cHhNVXY5MFZOc0tHdTBDSUE4Q0lMa3ZEZWg3NEFCRDB6QUNkbitBTkMyVVQ2Sk5UNnd6VHNLN3BYdUwKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==" + + return eCertBase64 +} + +func createKeyValuePairs(m map[string]uint64) string { + b := new(bytes.Buffer) + for key, value := range m { + fmt.Fprintf(b, "%s=\"%d\"\n", key, value) + } + return b.String() +} diff --git a/weaver/sdks/fabric/interoperation-node-sdk/index.js b/weaver/sdks/fabric/interoperation-node-sdk/index.js index 34293f16e7..53d21b5455 100644 --- a/weaver/sdks/fabric/interoperation-node-sdk/index.js +++ b/weaver/sdks/fabric/interoperation-node-sdk/index.js @@ -15,6 +15,7 @@ module.exports.RelayHelper = require("./src/Relay.js"); module.exports.InteroperableHelper = require("./src/InteroperableHelper.js"); module.exports.AssetManager = require("./src/AssetManager.js"); +module.exports.SatpAssetManager = require("./src/SatpAssetManager.js"); module.exports.HashFunctions = require("./src/HashFunctions.js"); module.exports.EventsManager = require("./src/EventsManager.js"); module.exports.MembershipManager = require("./src/MembershipManager.js"); diff --git a/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts b/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts index d18813ecb3..772fb10e2e 100644 --- a/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts +++ b/weaver/sdks/fabric/interoperation-node-sdk/src/AssetManager.ts @@ -393,6 +393,64 @@ const claimFungibleAssetInHTLC = async ( return result; }; +const assignAsset = async ( + contract: Contract, + assetType: string, + assetID: string, + lockerECert: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, "", lockerECert); + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("AssignAsset") + const ccArgs = [assetExchangeAgreementStr, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`AssignAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + /** * Rollback step of a Hashed Time Lock Contract * - Reclaim a unique asset instance @@ -1031,6 +1089,7 @@ export { claimAssetInHTLC, claimAssetInHTLCusingContractId, claimFungibleAssetInHTLC, + assignAsset, reclaimAssetInHTLC, reclaimAssetInHTLCusingContractId, reclaimFungibleAssetInHTLC, diff --git a/weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts b/weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts new file mode 100644 index 0000000000..313c995765 --- /dev/null +++ b/weaver/sdks/fabric/interoperation-node-sdk/src/SatpAssetManager.ts @@ -0,0 +1,1111 @@ +/* + * Copyright IBM Corp. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * This file provides helper functions for interoperability operations. + **/ +/** End file docs */ + +import log4js from "log4js"; +import crypto from "crypto"; +import fabproto6 from "fabric-protos"; +import * as helpers from "./helpers"; +import assetLocksPb from "@hyperledger/cacti-weaver-protos-js/common/asset_locks_pb"; +import { Contract, ContractListener } from "fabric-network"; +import { Hash, SHA256, SHA512 } from "./HashFunctions" +const logger = log4js.getLogger("InteroperableHelper"); + + +// Create an asset exchange agreement structure +function createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, lockerECert) +{ + const assetExchangeAgreement = new assetLocksPb.AssetExchangeAgreement(); + assetExchangeAgreement.setAssettype(assetType); + assetExchangeAgreement.setId(assetID); + assetExchangeAgreement.setRecipient(recipientECert); + assetExchangeAgreement.setLocker(lockerECert); + return Buffer.from(assetExchangeAgreement.serializeBinary()).toString('base64'); +} + +// Create a fungible asset exchange agreement structure +function createFungibleAssetExchangeAgreementSerialized(assetType, numUnits, recipientECert, lockerECert) +{ + const assetExchangeAgreement = new assetLocksPb.FungibleAssetExchangeAgreement(); + assetExchangeAgreement.setAssettype(assetType); + assetExchangeAgreement.setNumunits(numUnits); + assetExchangeAgreement.setRecipient(recipientECert); + assetExchangeAgreement.setLocker(lockerECert); + return Buffer.from(assetExchangeAgreement.serializeBinary()).toString('base64'); +} + +// Create an asset lock structure +function createAssetLockInfoSerialized(hash, expiryTimeSecs) +{ + const lockInfoHTLC = new assetLocksPb.AssetLockHTLC(); + lockInfoHTLC.setHashmechanism(hash.HASH_MECHANISM); + lockInfoHTLC.setHashbase64(Buffer.from(hash.getSerializedHashBase64())); + lockInfoHTLC.setExpirytimesecs(expiryTimeSecs); + lockInfoHTLC.setTimespec(assetLocksPb.TimeSpec.EPOCH); + const lockInfoHTLCSerialized = lockInfoHTLC.serializeBinary(); + const lockInfo = new assetLocksPb.AssetLock(); + lockInfo.setLockmechanism(assetLocksPb.LockMechanism.HTLC); + lockInfo.setLockinfo(lockInfoHTLCSerialized); + return Buffer.from(lockInfo.serializeBinary()).toString('base64'); +} + +// Create an asset claim structure +function createAssetClaimInfoSerialized(hash) +{ + const claimInfoHTLC = new assetLocksPb.AssetClaimHTLC(); + claimInfoHTLC.setHashmechanism(hash.HASH_MECHANISM); + claimInfoHTLC.setHashpreimagebase64(Buffer.from(hash.getSerializedPreimageBase64())); + const claimInfoHTLCSerialized = claimInfoHTLC.serializeBinary(); + const claimInfo = new assetLocksPb.AssetClaim(); + claimInfo.setLockmechanism(assetLocksPb.LockMechanism.HTLC); + claimInfo.setClaiminfo(claimInfoHTLCSerialized); + return Buffer.from(claimInfo.serializeBinary()).toString('base64'); +} + +/** + * First/second step of a Hashed Time Lock Contract + * - Lock a unique asset instance using a hash + * + * Byzantine Swaps: Call StartHTLCAssetLockListener within here while passing new callback + * parameter as newly defined function: assetLockExpirationCallback is passed as localCallback + **/ +const createHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + recipientECert: string, + hash: Hash, + expiryTimeSecs: number, + timeoutCallback: (c: Contract, t: string, i: string, r: string, h: Hash) => any, + endorsingOrgs: Array = [], +): Promise<{ hash: Hash; result: any }> => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return { hash: null, result: false }; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return { hash: null, result: false }; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return { hash: null, result: false }; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return { hash: null, result: false }; + } + const currTimeSecs = Math.floor(Date.now()/1000); // Convert epoch milliseconds to seconds + if (expiryTimeSecs <= currTimeSecs) + { + logger.error("Supplied expiry time invalid or in the past: %s; current time: %s", new Date(expiryTimeSecs).toISOString(), new Date(currTimeSecs).toISOString()); + return { hash: null, result: false }; + } + + if (hash == null) { + hash = new SHA256() + } + if (hash.hash64 == null) { + hash.generateRandomPreimage(22); + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, ""); + const lockInfoStr = createAssetLockInfoSerialized(hash, expiryTimeSecs); + + //If timeoutCallback is not defined, start automated listener + if (!timeoutCallback) + { + StartHTLCAssetLockListener(contract, "", assetType, assetID, recipientECert, "", assetLockExpirationCallback, endorsingOrgs); + } + + const tx = contract.createTransaction("LockAsset") + const ccArgs = [assetExchangeAgreementStr, lockInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + // Normal invoke function + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`LockAsset submitTransaction Error: ${submitError}`); + } + + if (timeoutCallback) + { + // Start timer for lock expiration + setTimeout(timeoutCallback, (expiryTimeSecs * 1000) - Date.now(), contract, assetType, assetID, recipientECert, hash); + } + + return { hash: hash, result: result }; +}; + +/** + * First/second step of a Hashed Time Lock Contract + * - Lock a set of fungible assets using a hash + **/ +const createFungibleHTLC = async ( + contract: Contract, + assetType: string, + numUnits: number, + recipientECert: string, + hash: Hash, + expiryTimeSecs: number, + timeoutCallback: (c: Contract, i: string, t: string, n: number, r: string, h: Hash) => any, + endorsingOrgs: Array = [], +): Promise<{ hash: Hash; result: any }> => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return { hash: null, result: "" }; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return { hash: null, result: "" }; + } + if (numUnits <= 0) + { + logger.error("Asset count must be a positive integer"); + return { hash: null, result: "" }; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return { hash: null, result: "" }; + } + const currTimeSecs = Math.floor(Date.now()/1000); // Convert epoch milliseconds to seconds + if (expiryTimeSecs <= currTimeSecs) + { + logger.error("Supplied expiry time invalid or in the past: %s; current time: %s", new Date(expiryTimeSecs).toISOString(), new Date(currTimeSecs).toISOString()); + return { hash: null, result: "" }; + } + + if (!hash) { + hash = new SHA256() + } + if (hash.hash64 == null) { + hash.generateRandomPreimage(22); + } + + const assetExchangeAgreementStr = createFungibleAssetExchangeAgreementSerialized(assetType, numUnits, recipientECert, ""); + const lockInfoStr = createAssetLockInfoSerialized(hash, expiryTimeSecs); + + //If timeoutCallback is not defined, start automated listener + if (!timeoutCallback) + { + StartHTLCFungibleAssetLockListener(contract, "", assetType, numUnits, recipientECert, "", fungibleAssetLockExpirationCallback, endorsingOrgs); + } + + const tx = contract.createTransaction("LockFungibleAsset") + const ccArgs = [assetExchangeAgreementStr, lockInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + // Normal invoke function + const [contractId, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`LockFungibleAsset submitTransaction Error: ${submitError}`); + } + + if (timeoutCallback) + { + // Start timer for lock expiration + setTimeout(timeoutCallback, (expiryTimeSecs * 1000) - Date.now(), contract, contractId, assetType, numUnits, recipientECert, hash); + } + + return { hash: hash, result: contractId }; +}; + +/** + * Latter step of a Hashed Time Lock Contract + * - Claim a unique asset instance using a hash preimage + **/ +const claimAssetInHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + lockerECert: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, "", lockerECert); + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("ClaimAsset") + const ccArgs = [assetExchangeAgreementStr, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`ClaimAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +const assignAsset = async ( + contract: Contract, + assetType: string, + assetID: string, + lockerECert: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, "", lockerECert); + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("AssignAsset") + const ccArgs = [assetExchangeAgreementStr, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`AssignAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Latter step of a Hashed Time Lock Contract + * - Claim a unique asset instance using a hash preimage and contractId + **/ +const claimAssetInHTLCusingContractId = async ( + contract: Contract, + contractId: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("ClaimAssetUsingContractId") + const ccArgs = [contractId, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`ClaimAssetUsingContractId submitTransaction Error: ${submitError}`); + } + return result; +}; + + +/** + * Latter step of a Hashed Time Lock Contract + * - Claim a set of fungible assets using a hash preimage + **/ +const claimFungibleAssetInHTLC = async ( + contract: Contract, + contractId: string, + hash: Hash, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + if (!hash) + { + logger.error("Instance of Hash interface not supplied") + return false + } + if (!hash.preimage) + { + logger.error("Hash Preimage not supplied"); + return false; + } + + const claimInfoStr = createAssetClaimInfoSerialized(hash); + + // Normal invoke function + const tx = contract.createTransaction("ClaimFungibleAsset") + const ccArgs = [contractId, claimInfoStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`ClaimFungibleAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Rollback step of a Hashed Time Lock Contract + * - Reclaim a unique asset instance + **/ +const reclaimAssetInHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + recipientECert: string, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, ""); + + // Normal invoke function + const tx = contract.createTransaction("UnlockAsset") + const ccArgs = [assetExchangeAgreementStr] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`UnlockAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Rollback step of a Hashed Time Lock Contract + * - Reclaim a unique asset instance using contractId + **/ +const reclaimAssetInHTLCusingContractId = async ( + contract: Contract, + contractId: string, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const tx = contract.createTransaction("UnlockAssetUsingContractId") + const ccArgs = [contractId] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`UnlockAssetUsingContractId submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Rollback step of a Hashed Time Lock Contract + * - Reclaim a set of fungible assets + **/ +const reclaimFungibleAssetInHTLC = async ( + contract: Contract, + contractId: string, + endorsingOrgs: Array = [] +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const tx = contract.createTransaction("UnlockFungibleAsset") + const ccArgs = [contractId] + if (endorsingOrgs && endorsingOrgs.length > 0) { + tx.setEndorsingOrganizations(...endorsingOrgs) + } + const [result, submitError] = await helpers.handlePromise( + tx.submit(...ccArgs) + ); + if (submitError) { + throw new Error(`UnlockFungibleAsset submitTransaction Error: ${submitError}`); + } + return result; +}; + +/** + * Query the state of a Hashed Time Lock Contract + * - Determine if a unique asset instance is locked by a given party for another given party + **/ +const isAssetLockedInHTLC = async ( + contract: Contract, + assetType: string, + assetID: string, + recipientECert: string, + lockerECert: string, +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!assetType) + { + logger.error("Asset type not supplied"); + return false; + } + if (!assetID) + { + logger.error("Asset ID not supplied"); + return false; + } + if (!recipientECert) + { + logger.error("Recipient ECert not supplied"); + return false; + } + if (!lockerECert) + { + logger.error("Locker ECert not supplied"); + return false; + } + + const assetExchangeAgreementStr = createAssetExchangeAgreementSerialized(assetType, assetID, recipientECert, lockerECert); + + // Normal invoke function + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("IsAssetLocked", assetExchangeAgreementStr), + ); + if (evaluateError) { + throw new Error(`IsAssetLocked evaluateTransaction Error: ${evaluateError}`); + } + return result.toString() === "true"; +}; + +/** + * Query the state of a Hashed Time Lock Contract using contractId + * - Determine if a unique asset instance is locked by a given party for another given party + **/ +const isAssetLockedInHTLCqueryUsingContractId = async ( + contract: Contract, + contractId: string, +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("IsAssetLockedQueryUsingContractId", contractId), + ); + if (evaluateError) { + throw new Error(`IsAssetLockedQueryUsingContractId evaluateTransaction Error: ${evaluateError}`); + } + return result.toString() === "true"; +}; + +/** + * Query the state of a Hashed Time Lock Contract + * - Determine if a set of fungible assets is locked by a given party for another given party + **/ +const isFungibleAssetLockedInHTLC = async ( + contract: Contract, + contractId: string, +): Promise => { + + if (!contract) + { + logger.error("Contract handle not supplied"); + return false; + } + if (!contractId) + { + logger.error("contract ID not supplied"); + return false; + } + + // Normal invoke function + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("IsFungibleAssetLocked", contractId), + ); + if (evaluateError) { + throw new Error(`IsFungibleAssetLocked evaluateTransaction Error: ${evaluateError}`); + } + return result.toString() === "true"; +}; + + +/** + * HTLC Lifecycle Events + * - Developers should note that event emission and actions in response occur on a best effort basis. + * - Also, there is no guarantee that a particular event (lock, claim, reclaim) will ever get emitted + * - Therefore, the calling (or listening) logic should incorporate suitable fallbacks and timeouts. + **/ + +/** + * The below functions trigger callbacks passed as arguments when a matching event is received from the contract layer + **/ +const StartHTLCEventListener = ( + contract: Contract, + eventName: string, + contractId: string, + assetType: string, + assetId: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + eventCallback: Function, + endorsingOrgs: Array = [], +): void => { + const listener: ContractListener = async (event) => { + if (event.eventName === eventName) { + let assetLockContractInfo; + + if (eventName.includes('Fungible')) { + const eventInfo: assetLocksPb.FungibleAssetContractHTLC = assetLocksPb.FungibleAssetContractHTLC.deserializeBinary(event.payload); + assetLockContractInfo = eventInfo; + } + else { + const eventInfo: assetLocksPb.AssetContractHTLC = assetLocksPb.AssetContractHTLC.deserializeBinary(event.payload); + assetLockContractInfo = eventInfo; + } + const infoContractId = assetLockContractInfo.getContractid(); + if (contractId && contractId.length > 0) { + if (infoContractId.length > 0 && infoContractId !== contractId) { + return; + } + } + const infoAssetType = assetLockContractInfo.getAgreement().getAssettype(); + if (assetType && assetType.length > 0) { + if (infoAssetType.length > 0 && infoAssetType !== assetType) { + return; + } + } + let infoNumUnits: number, infoAssetId: string; + if (eventName.includes('Fungible')) { + infoNumUnits = assetLockContractInfo.getAgreement().getNumunits(); + if (infoNumUnits != numUnits) { + return; + } + } + else { + infoAssetId = assetLockContractInfo.getAgreement().getId(); + if (assetId && assetId.length > 0) { + if (infoAssetId.length > 0 && infoAssetId !== assetId) { + return; + } + } + } + const infoRecipient = assetLockContractInfo.getAgreement().getRecipient(); + if (recipientECert && recipientECert.length > 0) { + if (infoRecipient.length > 0 && infoRecipient !== recipientECert) { + return; + } + } + const infoLocker = assetLockContractInfo.getAgreement().getLocker(); + if (lockerECert && lockerECert.length > 0) { + if (infoLocker.length > 0 && infoLocker !== lockerECert) { + return; + } + } + // All filters passed + if (eventName === 'LockAsset' || eventName === 'LockFungibleAsset') { + const timeout = assetLockContractInfo.getLock().getExpirytimesecs(); + const hashBase64 = assetLockContractInfo.getLock().getHashbase64(); + let hash: Hash; + + const hashMechanism = assetLockContractInfo.getLock().getHashmechanism(); + if (hashMechanism === assetLocksPb.HashMechanism.SHA256) { + hash = new SHA256(); + } + else if (hashMechanism === assetLocksPb.HashMechanism.SHA512) { + hash = new SHA512(); + } + else { + throw new Error(`Hash Mechanism not supported`); + } + hash.setSerializedHashBase64(hashBase64); + // We only care about timeouts for locking the asset, not for the unlock itself + if (eventName === 'LockAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoAssetId, infoRecipient, infoLocker, hash, timeout, endorsingOrgs); + } + else { + eventCallback(contract, infoContractId, infoAssetType, infoNumUnits, infoRecipient, infoLocker, hash, timeout, endorsingOrgs); + } + } else if (eventName === 'ClaimAsset' || eventName === 'ClaimFungibleAsset') { + const hashPreimageBase64 = assetLockContractInfo.getClaim().getHashpreimagebase64(); + const hashPreimage: string = Buffer.from(hashPreimageBase64.toString(), 'base64').toString('utf8'); + if (eventName === 'ClaimAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoAssetId, infoRecipient, infoLocker, hashPreimage); + } + else { + eventCallback(contract, infoContractId, infoAssetType, infoNumUnits, infoRecipient, infoLocker, hashPreimage); + } + } + else if (eventName === 'UnlockAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoAssetId, infoRecipient, infoLocker); + } + else if (eventName === 'UnlockFungibleAsset') { + eventCallback(contract, infoContractId, infoAssetType, infoNumUnits, infoRecipient, infoLocker); + } + } + }; + contract.addContractListener(listener); +} + +const StartHTLCAssetLockListener = ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, + lockCallback: (c: Contract, d: string, t: string, i: string, r: string, l: string, v: Hash, timeout: number, eOrgs: Array) => any, + endorsingOrgs: Array = [], +): void => { + StartHTLCEventListener(contract, 'LockAsset', contractId, assetType, assetId, -1, recipientECert, lockerECert, lockCallback, endorsingOrgs); +} + +// NOTE: For Nonfungible Assets +// Byzantine Swaps: Timed counterpart for timed AssetLockListener for reversion +const assetLockExpirationCallback = ( + contract: Contract, + contractID: string, + assetType: string, + assetID: string, + recipientECert: string, + lockerECert: string, + hash: Hash, + expiryTime: number, + endorsingOrgs: Array = [] +): void => { + // Compare expiryTimeSec with currentTimeSec, which is number of milliseconds since epoch (L174) + const currTimeSecs = Math.floor(Date.now()/1000); + const reclaimCallback = async (contract: Contract, contractID: string) => { + // Check if asset hasn't been claimed yet. If true, do nothing. If false, either do the following cases: + const [islocked, isLockedQueryError] = await helpers.handlePromise(isAssetLockedInHTLCqueryUsingContractId(contract, contractID)); + if (islocked === false) { + // CASE #1: Check GetHTLCHashPreImageByContractId(contractId) + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("GetHTLCHashPreImageByContractId", contractID), + ); + + // CASE #2: If the function above returns ANY error, call reclaimAssetInHTLC + if (evaluateError) { + // Put retry logic in event of failure. Retry 3x and then give up if unsuccessful (temp solution for now; requires CORE changes) + // If it fails, retry for i (arbitrarily defined) more attempts until you quit + let i = 0; + do { + let [retryReclaimResult, retryReclaimableQueryError] = await helpers.handlePromise(reclaimAssetInHTLCusingContractId(contract, contractID, endorsingOrgs)); + if (!retryReclaimableQueryError) { + console.log("Nonfungible Asset unlocked successfully"); + break; + } + + i++; + } while (i < 3); + } + } + } + + // If you have time remaining, call setTimeout with reclaimCallback + if (expiryTime - currTimeSecs > 0) { + setTimeout(reclaimCallback, 1000 * (expiryTime - currTimeSecs), contract, contractID); + } else { + // If no time remaining, call the reclaim callback immediately + reclaimCallback(contract, contractID); + } +} + +//NOTE: FUNGIBLE counterpart +// Byzantine Swaps: Timed counterpart for timed AssetLockListener for reversion +const fungibleAssetLockExpirationCallback = ( + contract: Contract, + contractID: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + hash: Hash, + expiryTime: number, + endorsingOrgs: Array = [] +): void => { + // Compare expiryTimeSec with currentTimeSec, which is number of milliseconds since epoch (L174) + const currTimeSecs = Math.floor(Date.now()/1000); + const reclaimCallback = async (contract: Contract, contractID: string) => { + // Check if asset hasn't been claimed yet. If true, do nothing. If false, either do the following cases: + const [islocked, isLockedQueryError] = await helpers.handlePromise(isFungibleAssetLockedInHTLC(contract, contractID)); + + if (islocked === false) { + // CASE #1: Check GetHTLCHashPreImageByContractId(contractId) + const [result, evaluateError] = await helpers.handlePromise( + contract.evaluateTransaction("GetHTLCHashPreImageByContractId", contractID), + ); + + // CASE #2: If the function above returns ANY error, call reclaimAssetInHTLC + if (evaluateError) { + // Put retry logic in event of failure. Retry 3x and then give up if unsuccessful (temp solution for now; requires CORE changes) + // If it fails, retry for i (arbitrarily defined) more attempts until you quit + let i = 0; + do { + let [retryReclaimResult, retryReclaimableQueryError] = await helpers.handlePromise(reclaimFungibleAssetInHTLC(contract, contractID, endorsingOrgs)); + if (!retryReclaimableQueryError) { + console.log("Fungible Asset unlocked successfully"); + break; + } + + i++; + } while (i < 3); + } + } + } + + // If you have time remaining, call setTimeout with reclaimCallback + if (expiryTime - currTimeSecs > 0) { + setTimeout(reclaimCallback, 1000 * (expiryTime - currTimeSecs), contract, contractID); + } else { + // If no time remaining, call the reclaim callback immediately + reclaimCallback(contract, contractID); + } +} + +const StartHTLCAssetClaimListener = ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, + claimCallback: (c: Contract, d: string, t: string, i: string, r: string, l: string, p: string) => any, +): void => { + StartHTLCEventListener(contract, 'ClaimAsset', contractId, assetType, assetId, -1, recipientECert, lockerECert, claimCallback); +} + +const StartHTLCAssetUnlockListener = ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, + unlockCallback: (c: Contract, d: string, t: string, i: string, r: string, l: string) => any, +): void => { + StartHTLCEventListener(contract, 'UnlockAsset', contractId, assetType, assetId, -1, recipientECert, lockerECert, unlockCallback); +} + +const StartHTLCFungibleAssetLockListener = ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + lockCallback: (c: Contract, d: string, t: string, n: number, r: string, l: string, v: Hash, timeout: number, eOrgs: Array) => any, + endorsingOrgs: Array = [], +): void => { + StartHTLCEventListener(contract, 'LockFungibleAsset', contractId, assetType, "", numUnits, recipientECert, lockerECert, lockCallback, endorsingOrgs); +} + +const StartHTLCFungibleAssetClaimListener = ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + claimCallback: (c: Contract, d: string, t: string, n: number, r: string, l: string, p: string) => any, +): void => { + StartHTLCEventListener(contract, 'ClaimFungibleAsset', contractId, assetType, "", numUnits, recipientECert, lockerECert, claimCallback); +} + +const StartHTLCFungibleAssetUnlockListener = ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, + unlockCallback: (c: Contract, d: string, t: string, n: number, r: string, l: string) => any, +): void => { + StartHTLCEventListener(contract, 'UnlockFungibleAsset', contractId, assetType, "", numUnits, recipientECert, lockerECert, unlockCallback); +} + +/** + * The below functions return promises for HTLC events. + * Developers can use 'await' to synchronously manage asset swapping logic. + **/ + const HTLCAssetLocked = async ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForLock = (contract, contractId, assetType, assetId, recipientECert, lockerECert, hashValue) => { + resolve(hashValue); + }; + StartHTLCAssetLockListener(contract, contractId, assetType, assetId, recipientECert, lockerECert, waitForLock); + }); +} + +const HTLCAssetClaimed = async ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForClaim = (contract, contractId, assetType, assetId, recipientECert, lockerECert, hashPreimage) => { + resolve(hashPreimage); + }; + StartHTLCAssetClaimListener(contract, contractId, assetType, assetId, recipientECert, lockerECert, waitForClaim); + }); +} + +const HTLCAssetUnlocked = async ( + contract: Contract, + contractId: string, + assetType: string, + assetId: string, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForUnlock = (contract, contractId, assetType, assetId, recipientECert, lockerECert) => { + resolve(); + }; + StartHTLCAssetUnlockListener(contract, contractId, assetType, assetId, recipientECert, lockerECert, waitForUnlock); + }); +} + +const HTLCFungibleAssetLocked = async ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForLock = (contract, contractId, assetType, numUnits, recipientECert, lockerECert, hashValue) => { + resolve(hashValue); + }; + StartHTLCFungibleAssetLockListener(contract, contractId, assetType, numUnits, recipientECert, lockerECert, waitForLock); + }); +} + +const HTLCFungibleAssetClaimed = async ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForClaim = (contract, contractId, assetType, numUnits, recipientECert, lockerECert, hashPreimage) => { + resolve(hashPreimage); + }; + StartHTLCFungibleAssetClaimListener(contract, contractId, assetType, numUnits, recipientECert, lockerECert, waitForClaim); + }); +} + +const HTLCFungibleAssetUnlocked = async ( + contract: Contract, + contractId: string, + assetType: string, + numUnits: number, + recipientECert: string, + lockerECert: string, +): Promise => { + return new Promise((resolve, reject) => { + const waitForUnlock = (contract, contractId, assetType, numUnits, recipientECert, lockerECert) => { + resolve(); + }; + StartHTLCFungibleAssetUnlockListener(contract, contractId, assetType, numUnits, recipientECert, lockerECert, waitForUnlock); + }); +} + +export { + createAssetExchangeAgreementSerialized, + createFungibleAssetExchangeAgreementSerialized, + createAssetLockInfoSerialized, + createAssetClaimInfoSerialized, + createHTLC, + createFungibleHTLC, + claimAssetInHTLC, + claimAssetInHTLCusingContractId, + claimFungibleAssetInHTLC, + reclaimAssetInHTLC, + reclaimAssetInHTLCusingContractId, + reclaimFungibleAssetInHTLC, + assignAsset, + isAssetLockedInHTLC, + isAssetLockedInHTLCqueryUsingContractId, + isFungibleAssetLockedInHTLC, + StartHTLCAssetLockListener, + StartHTLCAssetClaimListener, + StartHTLCAssetUnlockListener, + StartHTLCFungibleAssetLockListener, + StartHTLCFungibleAssetClaimListener, + StartHTLCFungibleAssetUnlockListener, + HTLCAssetLocked, + HTLCAssetClaimed, + HTLCAssetUnlocked, + HTLCFungibleAssetLocked, + HTLCFungibleAssetClaimed, + HTLCFungibleAssetUnlocked, +}; diff --git a/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts b/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts index 4ec78c0f11..f965212e3e 100644 --- a/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts +++ b/weaver/sdks/fabric/interoperation-node-sdk/types/index.d.ts @@ -14,6 +14,8 @@ import * as RelayHelper from "../src/Relay"; export { RelayHelper }; import * as AssetManager from "../src/AssetManager"; export { AssetManager }; +import * as SatpAssetManager from "../src/SatpAssetManager"; +export { SatpAssetManager }; import * as HashFunctions from "../src/HashFunctions"; export { HashFunctions }; import * as EventsManager from "../src/EventsManager"; diff --git a/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh b/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh index fd16f38531..6daf76491d 100755 --- a/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh +++ b/weaver/tests/network-setups/fabric/dev/scripts/deployCC.sh @@ -302,6 +302,10 @@ chaincodeInvokeInit() { peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Bond", "interop"]}' >&log.txt elif [ "$CC_CHAIN_CODE" = "simpleasset" ] && [ "$NW_NAME" = "network2" ]; then peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Token", "interop"]}' >&log.txt + elif [ "$CC_CHAIN_CODE" = "satpsimpleasset" ] && [ "$NW_NAME" = "network1" ]; then + peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Bond", "interop"]}' >&log.txt + elif [ "$CC_CHAIN_CODE" = "satpsimpleasset" ] && [ "$NW_NAME" = "network2" ]; then + peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["Token", "interop"]}' >&log.txt elif [ "$CC_CHAIN_CODE" = "simpleassettransfer" ] && [ "$NW_NAME" = "network1" ]; then peer chaincode invoke -o localhost:${ORD_P} --ordererTLSHostnameOverride orderer.$NW_NAME.com --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n $CC_CHAIN_CODE $PEER_CONN_PARMS --isInit -c '{"function":"initLedger","Args":["interop", "network1"]}' >&log.txt elif [ "$CC_CHAIN_CODE" = "simpleassettransfer" ] && [ "$NW_NAME" = "network2" ]; then From 410e843be9e2447857485bdc64927ca98cc0122b Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 3 Oct 2023 07:58:40 +0100 Subject: [PATCH 42/59] Initial documentation on how to run the satp gateway and test it --- weaver/core/relay/docs/README.md | 138 +++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 weaver/core/relay/docs/README.md diff --git a/weaver/core/relay/docs/README.md b/weaver/core/relay/docs/README.md new file mode 100644 index 0000000000..205b902761 --- /dev/null +++ b/weaver/core/relay/docs/README.md @@ -0,0 +1,138 @@ +# SATP Gateway + +The Weaver rely has been augmented to include the SATP implementation. Here are the steps to run and test this implementation: + +## Run two test Fabric networks +``` +$ cd weaver/tests/network-setups/fabric/dev +$ make start-interop-local CHAINCODE_NAME=satpsimpleasset +``` + +## Run the gateway + +In a new terminal, run the following commands: +``` +$ cd weaver/core/relay +$ RELAY_CONFIG=config/Dummy_Relay.toml cargo run --bin server +``` + +## Run the Fabric driver + +Ensure that you have the correct configuration in the file .env +In a new terminal, run the following commands: + +``` +$ cd weaver/core/drivers/fabric-driver +$ cat .env + +CONNECTION_PROFILE=/home/user/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json +RELAY_ENDPOINT=localhost:9085 +RELAY_TLS=false +RELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay +DRIVER_ENDPOINT=localhost:9090 +DRIVER_TLS=false +DRIVER_TLS_CERT_PATH=path_to_tls_cert_pem_for_driver +DRIVER_TLS_KEY_PATH=path_to_tls_key_pem_for_driver +NETWORK_NAME=network1 +DRIVER_CONFIG= +INTEROP_CHAINCODE=interop +MOCK=false +DB_PATH=driverdbs +#WALLET_PATH=/home/user/cacti/weaver/samples/fabric/fabric-cli/src/wallet-network1 +WALLET_PATH=/home/user/cacti/weaver/core/drivers/fabric-driver/wallet-network1 +DEBUG=true +LEVELDB_LOCKED_MAX_RETRIES= +LEVELDB_LOCKED_RETRY_BACKOFF_MSEC= +ENABLE_MONITOR=false +MONITOR_SYNC_PERIOD= +MEMBER_CREDENTIAL_FOLDER=/home/user/cacti/weaver/samples/fabric/fabric-cli/src/data/credentials +CONFIG_PATH=/home/user/cacti/weaver/samples/fabric/fabric-cli/config.json +DEFAULT_APPLICATION_CHAINCODE=simpleassettransfer +REMOTE_CONFIG_PATH=/home/user/cacti/weaver/samples/fabric/fabric-cli/remote-network-config.json +CHAINCODE_PATH=/home/user/cacti/weaver/samples/fabric/fabric-cli/chaincode.json + +``` + +Run the driver + +``` +$ cd weaver/core/drivers/fabric-driver +$ make build-local +$ npm run dev +``` + +# Build the satpsimpleasset chaincode + +In a new terminal, run the following commands: + +``` +$ cd weaver/samples/fabric/satpsimpleasset +$ make build-local +``` + +# Run the Fabric cli + +The Fabric-cli could be used for creating testing assets. Ensure you have the correct configuration. In a new terminal, run the following commands: + +``` +$ cd weaver/samples/fabric/fabric-cli +$ cat config.json + +{`` + "network1": { + "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json", + "relayEndpoint": "localhost:9080", + "mspId": "Org1MSP", + "channelName": "mychannel", + "chaincode": "satpsimpleasset", + "aclPolicyPrincipalType": "ca" + }, + "network2": { + "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json", + "relayEndpoint": "localhost:9083", + "mspId": "Org1MSP", + "channelName": "mychannel", + "chaincode": "satpsimpleasset", + "aclPolicyPrincipalType": "certificate" + } +} +``` + +Create sample assets: + +``` +$ cd weaver/samples/fabric/fabric-cli +$ ./bin/fabric-cli configure asset add --target-network=network1 --type=bond --data-file=./src/data/assets.json + +``` + +Ensure Alice and Bob ids are available: + +``` +$~/cacti/weaver/samples/fabric/fabric-cli/src/wallet-network1$ cp alice.id /home/user/cacti/weaver/core/drivers/fabric-driver/wallet-network1 +$~/cacti/weaver/samples/fabric/fabric-cli/src/wallet-network1$ cp bob.id /home/user/cacti/weaver/core/drivers/fabric-driver/wallet-network1 +$~/cacti/weaver/samples/fabric/fabric-cli/src/wallet-network1$ cd ../wallet-network2 +$~/cacti/weaver/samples/fabric/fabric-cli/src/wallet-network2$ cp alice.id /home/user/cacti/weaver/core/drivers/fabric-driver/wallet-network2 +$~/cacti/weaver/samples/fabric/fabric-cli/src/wallet-network2$ cp bob.id /home/user/cacti/weaver/core/drivers/fabric-driver/wallet-network2 + +``` + +## Run the client + +This client will trigger the SATP protocol by sending an asset transfer request. In a new terminal, run the following commands: + +``` +$ cd weaver/core/relay +$ cargo run --bin satp_client "9085" "localhost:9085/Dummy_Network/abc:abc:abc:abc" + +``` + +You should noticed that the messages started to be exchanged between the two gateways. The logs can be seen in the corresponding terminals. + + +## Run the gateway unit tests +``` +$ cd weaver/core/relay +$ cargo test --bin server + +``` \ No newline at end of file From cae117a5db7524cece97db577d18dbc3608563d0 Mon Sep 17 00:00:00 2001 From: Rafael Belchior Date: Fri, 6 Oct 2023 13:32:51 +0300 Subject: [PATCH 43/59] feat(weaver): add application logs --- .../src/test/rust/ink/flipper/Cargo.lock | 708 ++++++++++++++++++ weaver/core/relay/.env.template | 1 + weaver/core/relay/.env.template.2 | 1 + weaver/core/relay/Cargo.lock | 588 ++++++++------- weaver/core/relay/Cargo.toml | 2 + weaver/core/relay/README.md | 5 + weaver/core/relay/src/main.rs | 19 +- weaver/core/relay/src/services/helpers.rs | 5 +- weaver/core/relay/src/services/logger.rs | 6 + 9 files changed, 1049 insertions(+), 286 deletions(-) create mode 100644 packages/cactus-plugin-ledger-connector-polkadot/src/test/rust/ink/flipper/Cargo.lock create mode 100644 weaver/core/relay/src/services/logger.rs diff --git a/packages/cactus-plugin-ledger-connector-polkadot/src/test/rust/ink/flipper/Cargo.lock b/packages/cactus-plugin-ledger-connector-polkadot/src/test/rust/ink/flipper/Cargo.lock new file mode 100644 index 0000000000..6c2ecdf37a --- /dev/null +++ b/packages/cactus-plugin-ledger-connector-polkadot/src/test/rust/ink/flipper/Cargo.lock @@ -0,0 +1,708 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "array-init" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb6d71005dc22a708c7496eee5c8dc0300ee47355de6256c3b35b12b5fef596" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b12e5fd123190ce1c2e559308a94c9bacad77907d4c6005d9e58fe1a0689e55e" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "cc" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "flipper" +version = "0.1.0" +dependencies = [ + "ink_env", + "ink_lang", + "ink_metadata", + "ink_primitives", + "ink_storage", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ink_allocator" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c9588a59a0e8997c0b2153cd11b5aaa77c06a0537a6b18f3811d1f1aa098b12" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ink_engine" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487c3b390b7feb0620496b0cd38683433c7d7e6946b1caabda51e1f23eb24b30" +dependencies = [ + "blake2", + "derive_more", + "parity-scale-codec", + "rand", + "secp256k1", + "sha2", + "sha3", +] + +[[package]] +name = "ink_env" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a891d34301a3dbb1c7b7424c49ae184282b163491c54f9acd17fcbe14a80447b" +dependencies = [ + "arrayref", + "blake2", + "cfg-if", + "derive_more", + "ink_allocator", + "ink_engine", + "ink_metadata", + "ink_prelude", + "ink_primitives", + "num-traits", + "parity-scale-codec", + "paste", + "rand", + "rlibc", + "scale-info", + "secp256k1", + "sha2", + "sha3", + "static_assertions", +] + +[[package]] +name = "ink_lang" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cca26e374e0f89c82cf5dabb4309ef3c76a01659ad95186f4e84455c5f4621a0" +dependencies = [ + "derive_more", + "ink_env", + "ink_lang_macro", + "ink_prelude", + "ink_primitives", + "ink_storage", + "parity-scale-codec", +] + +[[package]] +name = "ink_lang_codegen" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fe57826726d89c84fe0b1fafe0dee328f58c8e927be40f0290f04602aacc45c" +dependencies = [ + "blake2", + "derive_more", + "either", + "heck", + "impl-serde", + "ink_lang_ir", + "itertools", + "parity-scale-codec", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ink_lang_ir" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47d16b2a5340df90f11b2ec2242b37907f5c8396dbbc72c52ec9f2b1a8c90c8" +dependencies = [ + "blake2", + "either", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ink_lang_macro" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b858be42ac6cde2c15ce6d7fa75cef59b64a3baf37f7105f39208f2b84dadb" +dependencies = [ + "ink_lang_codegen", + "ink_lang_ir", + "ink_primitives", + "parity-scale-codec", + "proc-macro2", + "syn", +] + +[[package]] +name = "ink_metadata" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74913aaed5751f5615af4631b7559328b8ed56c9cb821b89e14af0706176e849" +dependencies = [ + "derive_more", + "impl-serde", + "ink_prelude", + "ink_primitives", + "scale-info", + "serde", +] + +[[package]] +name = "ink_prelude" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f031e6b8495594a7288b089bf4122e76c26b994959d1b2b693bdfe846b14c0e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ink_primitives" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12cf42dce81d060401c7cec95a392ad6d3c2f18661fa3083f619ce135133c33" +dependencies = [ + "cfg-if", + "ink_prelude", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "ink_storage" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c0a98b6acbd79eedf44720412437d713e7195d1407822604de5885b0ee6c7e1" +dependencies = [ + "array-init", + "cfg-if", + "derive_more", + "ink_env", + "ink_metadata", + "ink_prelude", + "ink_primitives", + "ink_storage_derive", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "ink_storage_derive" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "babf1d8903dc9219ad8e8aa181eddb919d9794aad1da23ccdce770925b7de2ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "parity-scale-codec" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "366e44391a8af4cfd6002ef6ba072bae071a96aafca98d7d448a34c5dca38b6a" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9299338969a3d2f491d65f140b00ddec470858402f888af98e8642fb5e8965cd" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "paste" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-crate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +dependencies = [ + "once_cell", + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rlibc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" + +[[package]] +name = "scale-info" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d8a765117b237ef233705cc2cc4c6a27fccd46eea6ef0c8c6dae5f3ef407f8" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", + "serde", +] + +[[package]] +name = "scale-info-derive" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcd47b380d8c4541044e341dcd9475f55ba37ddc50c908d945fc036a8642496" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "secp256k1" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff55dc09d460954e9ef2fa8a7ced735a964be9981fd50e870b2b3b0705e14964" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +dependencies = [ + "cc", +] + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/weaver/core/relay/.env.template b/weaver/core/relay/.env.template index 7acde819d3..9960d79ed6 100644 --- a/weaver/core/relay/.env.template +++ b/weaver/core/relay/.env.template @@ -6,3 +6,4 @@ DOCKER_TAG=2.0.0-alpha.1 EXTERNAL_NETWORK= COMPOSE_PROJECT_NAME= COMPOSE_PROJECT_NETWORK= +RUST_LOG="DEBUG" diff --git a/weaver/core/relay/.env.template.2 b/weaver/core/relay/.env.template.2 index e2a427b88e..ba92e6e0b0 100644 --- a/weaver/core/relay/.env.template.2 +++ b/weaver/core/relay/.env.template.2 @@ -18,3 +18,4 @@ RELAY_TLS_CERT_PATH= RELAY_TLS_KEY_PATH= DRIVER_TLS=false DRIVER_TLSCA_CERT_PATH= +RUST_LOG="DEBUG" diff --git a/weaver/core/relay/Cargo.lock b/weaver/core/relay/Cargo.lock index ed534ff613..a69eed1fa8 100644 --- a/weaver/core/relay/Cargo.lock +++ b/weaver/core/relay/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -19,18 +19,18 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arrayvec" @@ -57,18 +57,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] @@ -79,9 +79,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", @@ -98,7 +98,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustversion", - "serde 1.0.164", + "serde 1.0.188", "sync_wrapper", "tower", "tower-layer", @@ -124,9 +124,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -151,9 +151,9 @@ checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "bincode" @@ -161,7 +161,7 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "serde 1.0.164", + "serde 1.0.188", ] [[package]] @@ -178,36 +178,39 @@ checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cacti_weaver_protos_rs" version = "2.0.0-alpha.1" dependencies = [ "prost", - "serde 1.0.164", + "serde 1.0.188", "tonic", ] [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -223,7 +226,7 @@ checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ "is-terminal", "lazy_static", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -235,7 +238,7 @@ dependencies = [ "lazy_static", "nom", "rust-ini", - "serde 1.0.164", + "serde 1.0.188", "serde-hjson", "serde_json", "toml", @@ -291,28 +294,47 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -327,12 +349,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fixedbitset" @@ -436,7 +455,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] @@ -491,15 +510,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ "bytes", "fnv", @@ -507,7 +526,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -520,6 +539,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" + [[package]] name = "heck" version = "0.4.1" @@ -528,9 +553,18 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] [[package]] name = "http" @@ -562,9 +596,15 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" @@ -583,7 +623,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -632,27 +672,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] -name = "instant" -version = "0.1.12" +name = "indexmap" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ - "cfg-if", + "equivalent", + "hashbrown 0.14.1", ] [[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", + "cfg-if", ] [[package]] @@ -668,8 +707,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.9", - "windows-sys 0.48.0", + "rustix", + "windows-sys", ] [[package]] @@ -683,9 +722,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" @@ -717,9 +756,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.148" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" [[package]] name = "linked-hash-map" @@ -729,15 +768,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db" [[package]] name = "listenfd" @@ -762,21 +795,21 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "matchit" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" @@ -795,9 +828,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] @@ -810,7 +843,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -854,14 +887,14 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" dependencies = [ - "num-traits 0.2.15", + "num-traits 0.2.16", ] [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] @@ -878,9 +911,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] @@ -893,11 +926,11 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cfg-if", "foreign-types", "libc", @@ -914,7 +947,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] @@ -925,9 +958,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" dependencies = [ "cc", "libc", @@ -968,39 +1001,39 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "petgraph" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 2.0.2", ] [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1032,9 +1065,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "5b1106fec09662ec6dd98ccac0f81cef56984d0b49f75c92d8cbad76e20c005c" dependencies = [ "unicode-ident", ] @@ -1095,9 +1128,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.29" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1152,9 +1185,21 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" dependencies = [ "aho-corasick", "memchr", @@ -1163,9 +1208,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "relay" @@ -1176,10 +1221,12 @@ dependencies = [ "cacti_weaver_protos_rs", "colored", "config", + "env_logger", "futures", "listenfd", + "log", "reqwest", - "serde 1.0.164", + "serde 1.0.188", "serde_json", "sled", "tokio", @@ -1190,11 +1237,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64 0.21.2", + "base64 0.21.4", "bytes", "encoding_rs", "futures-core", @@ -1212,9 +1259,10 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "serde 1.0.164", + "serde 1.0.188", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -1254,36 +1302,22 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.20" +version = "0.38.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" +checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7" dependencies = [ "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys 0.4.5", - "windows-sys 0.48.0", + "linux-raw-sys", + "windows-sys", ] [[package]] name = "rustls" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" dependencies = [ "log", "ring", @@ -1297,35 +1331,35 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.2", + "base64 0.21.4", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys", ] [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" @@ -1339,9 +1373,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -1352,9 +1386,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -1368,9 +1402,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] @@ -1389,24 +1423,24 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ "itoa", "ryu", - "serde 1.0.164", + "serde 1.0.188", ] [[package]] @@ -1418,14 +1452,14 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde 1.0.164", + "serde 1.0.188", ] [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -1448,9 +1482,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "socket2" @@ -1462,6 +1496,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "spin" version = "0.5.2" @@ -1487,9 +1531,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.22" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -1502,18 +1546,47 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" -version = "3.6.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ - "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.20", - "windows-sys 0.48.0", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +dependencies = [ + "winapi-util", ] [[package]] @@ -1533,20 +1606,19 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.0" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374442f06ee49c3a28a8fc9f01a2596fed7559c6b99b31279c3261778e77d84f" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", - "socket2", + "socket2 0.5.4", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1567,7 +1639,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] @@ -1604,9 +1676,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" dependencies = [ "bytes", "futures-core", @@ -1622,7 +1694,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "serde 1.0.164", + "serde 1.0.188", ] [[package]] @@ -1680,7 +1752,7 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 1.9.3", "pin-project", "pin-project-lite", "rand", @@ -1724,7 +1796,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", ] [[package]] @@ -1760,9 +1832,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -1781,9 +1853,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", @@ -1792,9 +1864,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" dependencies = [ "getrandom", ] @@ -1847,7 +1919,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -1881,7 +1953,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1904,9 +1976,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.22.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0e74f82d49d545ad128049b7e88f6576df2da6b02e9ce565c6f533be576957e" +checksum = "07ecc0cd7cac091bf682ec5efa18b1cff79d617b84181f38b3951dbe135f607f" dependencies = [ "ring", "untrusted", @@ -1914,13 +1986,14 @@ dependencies = [ [[package]] name = "which" -version = "4.4.0" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ "either", - "libc", + "home", "once_cell", + "rustix", ] [[package]] @@ -1940,25 +2013,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "winapi-util" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] [[package]] -name = "windows-sys" -version = "0.42.0" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" @@ -1971,110 +2038,69 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys", ] [[package]] diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index 43fa28f188..cfc72e9f58 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -40,6 +40,8 @@ serde_json = "1.0.95" # cacti_weaver_protos_rs = "2.0.0-alpha.1" cacti_weaver_protos_rs = { path = "../../common/protos-rs/pkg" } colored = {version="2.0.4"} +log = "0.4.20" +env_logger = "0.10.0" [build-dependencies] tonic-build = "0.8.4" diff --git a/weaver/core/relay/README.md b/weaver/core/relay/README.md index af709ce41f..f864902de8 100644 --- a/weaver/core/relay/README.md +++ b/weaver/core/relay/README.md @@ -49,6 +49,11 @@ Corda example: `localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H` +## Logging +We use a simple logger for messaging. In the future we can use ``log4rs``to persist applicational log. +On the other hand, we persist message flow payloads, but we want to support the [gateway crash-recovery logging procedure](https://www.techrxiv.org/articles/preprint/HERMES_Fault-Tolerant_Middleware_for_Blockchain_Interoperability/14120291). + + ### Settings The `Settings.toml` file is used for storing configurations as well as acting as the remote relay discovery service. diff --git a/weaver/core/relay/src/main.rs b/weaver/core/relay/src/main.rs index 9ae14935fe..53987979c7 100644 --- a/weaver/core/relay/src/main.rs +++ b/weaver/core/relay/src/main.rs @@ -2,6 +2,8 @@ // // SPDX-License-Identifier: Apache-2.0 +use log::debug; +use log::info; // Internal generated modules use weaverpb::networks::networks::network_server::NetworkServer; use weaverpb::relay::datatransfer::data_transfer_server::DataTransferServer; @@ -38,7 +40,18 @@ async fn main() -> Result<(), Box> { println!("Using default config `config/Settings`"); "config/Settings".to_string() }); + let log_level = env::var("RUST_LOG").unwrap_or_else(|_| { + println!("Using default log level"); + return "debug".to_string(); + }); + println!("Log level: {}", log_level); + + // Set the RUST_LOG environment variable + env::set_var("RUST_LOG", &log_level); + // Initialize the logger + env_logger::init(); + settings .merge(config::File::with_name(&config_file_name)) .unwrap() @@ -47,7 +60,7 @@ async fn main() -> Result<(), Box> { .unwrap(); let relay_name = settings.get_str("name").expect("No Relay name provided"); - println!("Relay Name: {:?}", relay_name); + info!("Relay Name: {:?}", relay_name); let relay_port = settings.get_str("port").expect(&format!("Port does not exist for relay name {}. Make sure the config file <{}> has the name and port specified.", relay_name, config_file_name.to_string())); let host = settings .get_str("hostname") @@ -75,9 +88,9 @@ async fn main() -> Result<(), Box> { let network = NetworkService { config_lock: RwLock::new(settings.clone()), }; - println!("RelayServer listening on {}", addr); + info!("RelayServer listening on {}", addr); if with_tls == true { - println!("Starting Server with TLS"); + debug!("Starting Server with TLS"); let cert = tokio::fs::read(settings.get_str("cert_path").unwrap()).await?; let key = tokio::fs::read(settings.get_str("key_path").unwrap()).await?; let identity = Identity::from_pem(cert, key); diff --git a/weaver/core/relay/src/services/helpers.rs b/weaver/core/relay/src/services/helpers.rs index c3df19b069..d2df48e289 100644 --- a/weaver/core/relay/src/services/helpers.rs +++ b/weaver/core/relay/src/services/helpers.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use colored::Colorize; +use log::info; use weaverpb::common::ack::{ack}; use weaverpb::common::events::{event_subscription_state, EventSubscriptionState}; use weaverpb::common::events::{EventPublication, EventState, EventStates, EventSubscription}; @@ -509,7 +510,7 @@ pub fn get_event_publication_key(request_id: String) -> String { } pub fn println_stage_heading(stage_id: String) { - println!( + info!( "{} {} {}", "\n --------- Stage".yellow().bold(), stage_id.yellow().bold(), @@ -518,7 +519,7 @@ pub fn println_stage_heading(stage_id: String) { } pub fn println_step_heading(step_id: String) { - println!( + info!( "{} {} {}", "\n --------- Step".bright_cyan().bold(), step_id.bright_cyan().bold(), diff --git a/weaver/core/relay/src/services/logger.rs b/weaver/core/relay/src/services/logger.rs new file mode 100644 index 0000000000..a1c7d309f4 --- /dev/null +++ b/weaver/core/relay/src/services/logger.rs @@ -0,0 +1,6 @@ +use crate::error::Error; +use std::str::FromStr; + +pub fn init_logger_env() -> Result<(), Error> { + simple_logger::init_with_env().map_err(|e| Error::Logger(e.to_string())) +} From 33703d208af61c24777683f2d19c20ce7e24ffdf Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 16 Oct 2023 15:13:25 +0100 Subject: [PATCH 44/59] Initial log functionality --- weaver/core/relay/Cargo.lock | 144 ++++++++++++++++- weaver/core/relay/Cargo.toml | 3 + weaver/core/relay/docs/README.md | 7 + weaver/core/relay/src/services/database.rs | 97 +++++++++++ weaver/core/relay/src/services/mod.rs | 1 + weaver/core/relay/src/services/satp_helper.rs | 152 ++++++++++++------ .../core/relay/src/services/satp_service.rs | 88 +++++++--- 7 files changed, 420 insertions(+), 72 deletions(-) create mode 100644 weaver/core/relay/src/services/database.rs diff --git a/weaver/core/relay/Cargo.lock b/weaver/core/relay/Cargo.lock index ed534ff613..1f4d928cf1 100644 --- a/weaver/core/relay/Cargo.lock +++ b/weaver/core/relay/Cargo.lock @@ -17,6 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "1.0.2" @@ -26,6 +37,27 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anyhow" version = "1.0.71" @@ -215,6 +247,20 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits 0.2.15", + "wasm-bindgen", + "windows-targets", +] + [[package]] name = "colored" version = "2.0.4" @@ -289,6 +335,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "either" version = "1.8.1" @@ -325,6 +377,18 @@ dependencies = [ "libc", ] +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fastrand" version = "1.9.0" @@ -520,6 +584,25 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.1", +] + [[package]] name = "heck" version = "0.4.1" @@ -615,6 +698,29 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "idna" version = "0.4.0" @@ -632,7 +738,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -721,6 +827,16 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "libsqlite3-sys" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" +dependencies = [ + "pkg-config", + "vcpkg", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1174,11 +1290,14 @@ dependencies = [ "base64 0.20.0", "bincode", "cacti_weaver_protos_rs", + "chrono", "colored", "config", + "dotenv", "futures", "listenfd", "reqwest", + "rusqlite", "serde 1.0.164", "serde_json", "sled", @@ -1240,6 +1359,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "rusqlite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" +dependencies = [ + "bitflags 2.4.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rust-ini" version = "0.13.0" @@ -1945,6 +2078,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.42.0" diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index 43fa28f188..da64b2edb8 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -40,6 +40,9 @@ serde_json = "1.0.95" # cacti_weaver_protos_rs = "2.0.0-alpha.1" cacti_weaver_protos_rs = { path = "../../common/protos-rs/pkg" } colored = {version="2.0.4"} +rusqlite = "0.29.0" +chrono = "0.4" +dotenv = "0.15" [build-dependencies] tonic-build = "0.8.4" diff --git a/weaver/core/relay/docs/README.md b/weaver/core/relay/docs/README.md index 205b902761..21e1d0b628 100644 --- a/weaver/core/relay/docs/README.md +++ b/weaver/core/relay/docs/README.md @@ -10,6 +10,13 @@ $ make start-interop-local CHAINCODE_NAME=satpsimpleasset ## Run the gateway +Before running the gateway, you need to ensure SQLite (the default database for logs) is installed: + +``` +sudo apt-get update +sudo apt-get install libsqlite3-dev +``` + In a new terminal, run the following commands: ``` $ cd weaver/core/relay diff --git a/weaver/core/relay/src/services/database.rs b/weaver/core/relay/src/services/database.rs new file mode 100644 index 0000000000..c0c59b6388 --- /dev/null +++ b/weaver/core/relay/src/services/database.rs @@ -0,0 +1,97 @@ +use rusqlite::{params, Connection, Result}; +use serde::{Deserialize, Serialize}; +use std::error::Error; + +const SQLITE_DATABASE_FILE: &str = "gateway_log.db"; // Define a constant for the database filename + +// Define a Log struct that represents a log entry +pub struct Log { + pub timestamp: String, + pub request_id: String, + pub request: String, + pub step_id: String, + pub operation: Operation, + pub network_id: String, + pub gateway_id: String, + pub received: bool, + pub details: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Operation { + Init, + Exec, + Done, + Failed, +} + +impl std::string::ToString for Operation { + fn to_string(&self) -> String { + match self { + Operation::Init => "Init".to_string(), + Operation::Exec => "Exec".to_string(), + Operation::Done => "Done".to_string(), + Operation::Failed => "Failed".to_string(), + } + } +} + +pub trait Database { + fn log(&self, log: &Log) -> Result<(), Box>; +} + +pub struct SqliteDatabase; + +impl SqliteDatabase { + fn create_logs_table(&self) -> Result<(), Box> { + // Open a connection to the SQLite database file + let conn = Connection::open(SQLITE_DATABASE_FILE)?; // Replace "log.db" with your database file + + // Create a table to store log entries if it doesn't exist + conn.execute( + "CREATE TABLE IF NOT EXISTS logs ( + id INTEGER PRIMARY KEY, + timestamp TEXT, + request_id TEXT, + request TEXT, + step_id TEXT, + operation TEXT, + network_id TEXT, + gateway_id TEXT, + received TEXT, + details TEXT + )", + params![], + )?; + + Ok(()) + } +} + +impl Database for SqliteDatabase { + fn log(&self, log: &Log) -> Result<(), Box> { + // Ensure the logs table exists + self.create_logs_table()?; + + // Open a connection to the SQLite database file + let conn = Connection::open(SQLITE_DATABASE_FILE)?; + + // Insert the log entry into the database + conn.execute( + "INSERT INTO logs (timestamp, request_id, request, step_id, operation, network_id, gateway_id, received, details) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)", + &[&log.timestamp, &log.request_id, &log.request, &log.step_id, &log.operation.to_string(), &log.network_id, &log.gateway_id, &(if log.received { "1".to_string() } else { "0".to_string() }), &log.details.as_ref().unwrap_or(&"".to_string())] + )?; + + Ok(()) + } +} + +pub struct PostgresDatabase; + +impl Database for PostgresDatabase { + fn log(&self, log: &Log) -> Result<(), Box> { + // TODO: Implement the logging logic for PostgreSQL + Ok(()) + } +} diff --git a/weaver/core/relay/src/services/mod.rs b/weaver/core/relay/src/services/mod.rs index d24901e98a..f5f990722e 100644 --- a/weaver/core/relay/src/services/mod.rs +++ b/weaver/core/relay/src/services/mod.rs @@ -11,3 +11,4 @@ pub mod helpers; pub mod satp_helper; pub mod types; pub mod constants; +pub mod database; diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 61c13bf146..cab94d6cdd 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -22,6 +22,10 @@ use crate::db::Database; use crate::error::{self, Error}; use crate::relay_proto::LocationSegment; use crate::services::helpers::get_driver_client; +use dotenv::dotenv; +use chrono::Utc; +use crate::services::database::Operation; +use super::database::{Log, PostgresDatabase, SqliteDatabase}; use super::constants::{ SATP_DB_PATH, SATP_REMOTE_REQUESTS_DB_PATH, SATP_REMOTE_REQUESTS_STATES_DB_PATH, @@ -29,6 +33,34 @@ use super::constants::{ }; use super::types::Driver; +fn choose_database() -> Box { + // Choose the appropriate database type (e.g., based on an environment variable) + let use_sqlite = std::env::var("USE_SQLITE").is_ok(); + + // Create a database instance + if use_sqlite { + Box::new(SqliteDatabase) + } else { + Box::new(PostgresDatabase) + } +} + +fn add_log( + database: &dyn super::database::Database, + log: Log, +) -> Result<(), Box> { + // Log the entry using the provided database + database.log(&log)?; + Ok(()) +} + +pub fn log_request(log: Log) { + dotenv().ok(); + + let database = choose_database(); + add_log(&*database, log).unwrap(); +} + // Sends a request to the receiving gateway pub fn spawn_send_transfer_proposal_claims_request( transfer_proposal_claims_request: TransferProposalClaimsRequest, @@ -61,7 +93,7 @@ pub fn spawn_send_transfer_proposal_claims_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - log_request_result_in_local_satp_db(&request_id, result, conf); + log_request_result(&request_id, result); }); } @@ -96,7 +128,7 @@ pub fn spawn_send_transfer_commence_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - log_request_result_in_local_satp_db(&request_id, result, conf); + log_request_result(&request_id, result); }); } @@ -105,8 +137,7 @@ pub fn spawn_send_transfer_proposal_receipt_request( relay_host: String, relay_port: String, use_tls: bool, - tlsca_cert_path: String, - conf: Config, + tlsca_cert_path: String ) { tokio::spawn(async move { let request_id = get_request_id_from_transfer_proposal_receipt( @@ -116,6 +147,22 @@ pub fn spawn_send_transfer_proposal_receipt_request( "Sending transfer proposal receipt back to sending gateway: Request ID = {:?}", request_id ); + + let log = Log { + timestamp: Utc::now().naive_utc().to_string(), + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_proposal_receipt_request.clone()).unwrap(), + step_id: "1.2".to_string(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: transfer_proposal_receipt_request + .clone() + .sender_gateway_network_id, + received: false, + details: None, + }; + log_request(log); + let result = call_transfer_proposal_receipt( relay_host, relay_port, @@ -127,7 +174,7 @@ pub fn spawn_send_transfer_proposal_receipt_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - log_request_result_in_local_satp_db(&request_id, result, conf); + log_request_result(&request_id, result); }); } @@ -156,7 +203,7 @@ pub fn spawn_send_ack_commence_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - log_request_result_in_local_satp_db(&request_id, result, conf); + log_request_result(&request_id, result); }); } @@ -190,8 +237,7 @@ pub fn spawn_send_lock_assertion_broadcast_request( relay_host: String, relay_port: String, use_tls: bool, - tlsca_cert_path: String, - conf: Config, + tlsca_cert_path: String ) { tokio::spawn(async move { let request_id = lock_assertion_request.session_id.to_string(); @@ -216,7 +262,7 @@ pub fn spawn_send_lock_assertion_broadcast_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = lock_assertion_receipt_request.session_id.to_string(); - log_request_result_in_local_satp_db(&request_id, result, conf); + log_request_result(&request_id, result); }); } @@ -243,7 +289,7 @@ pub fn spawn_send_lock_assertion_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = lock_assertion_request.session_id.to_string(); - log_request_result_in_local_satp_db(&request_id, result, conf); + log_request_result(&request_id, result); }); } @@ -274,7 +320,7 @@ pub fn spawn_send_commit_prepare_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - log_request_result_in_local_satp_db(&request_id, result, conf); + log_request_result(&request_id, result); }); } @@ -326,7 +372,7 @@ pub fn spawn_send_commit_ready_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = commit_ready_request.session_id.to_string(); - log_request_result_in_local_satp_db(&request_id, result, conf); + log_request_result(&request_id, result); }); } @@ -378,7 +424,7 @@ pub fn spawn_send_ack_final_receipt_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = ack_final_receipt_request.session_id.to_string(); - log_request_result_in_local_satp_db(&request_id, result, conf); + log_request_result(&request_id, result); }); } @@ -415,7 +461,7 @@ pub fn spawn_send_ack_final_receipt_broadcast_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = transfer_completed_request.session_id.to_string(); - log_request_result_in_local_satp_db(&request_id, result, conf); + log_request_result(&request_id, result); }); } @@ -471,7 +517,7 @@ pub fn spawn_send_commit_final_assertion_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = commit_final_assertion_request.session_id.to_string(); - log_request_result_in_local_satp_db(&request_id, result, conf); + log_request_result(&request_id, result); }); } @@ -790,10 +836,9 @@ pub async fn call_commit_final_assertion_receipt( Ok(response) } -pub fn log_request_result_in_local_satp_db( +pub fn log_request_result( request_id: &String, result: Result, Box>, - conf: Config, ) { match result { Ok(ack_response) => { @@ -801,37 +846,54 @@ pub fn log_request_result_in_local_satp_db( // This match first checks if the status is valid. match ack::Status::from_i32(ack_response_into_inner.status) { Some(status) => match status { - ack::Status::Ok => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Pending, - None, - conf, - ), - ack::Status::Error => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Error, - Some(request_state::State::Error( - ack_response_into_inner.message.to_string(), - )), - conf, - ), + ack::Status::Ok => { + let log = Log { + timestamp: Utc::now().naive_utc().to_string(), + request_id: request_id.clone(), + request: "".to_string(), + step_id: "".to_string(), + operation: Operation::Done, + network_id: "".to_string(), + gateway_id: "".to_string(), + received: false, + details: None, + }; + log_request(log); + } + ack::Status::Error => { + let log = Log { + timestamp: Utc::now().naive_utc().to_string(), + request_id: request_id.clone(), + request: "".to_string(), + step_id: "".to_string(), + operation: Operation::Failed, + network_id: "".to_string(), + gateway_id: "".to_string(), + received: false, + details: Some(ack_response_into_inner.message), + }; + log_request(log); + } }, - None => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Error, - Some(request_state::State::Error( - "Status is not supported or is invalid".to_string(), - )), - conf, - ), + None => { + // TODO + } } } - Err(result_error) => update_request_state_in_local_satp_db( - request_id.to_string(), - request_state::Status::Error, - Some(request_state::State::Error(format!("{:?}", result_error))), - conf, - ), + Err(result_error) => { + let log = Log { + timestamp: Utc::now().naive_utc().to_string(), + request_id: request_id.clone(), + request: "".to_string(), + step_id: "".to_string(), + operation: Operation::Failed, + network_id: "".to_string(), + gateway_id: "".to_string(), + received: false, + details: Some(result_error.to_string()), + }; + log_request(log); + } } } diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 7ed1536339..2e81055572 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,3 +1,4 @@ +use chrono::Utc; // Internal generated modules use weaverpb::common::ack::{ack, Ack}; use weaverpb::driver::driver::{ @@ -14,12 +15,13 @@ use weaverpb::relay::satp::{ // Internal modules use crate::error::Error; use crate::relay_proto::parse_address; +use crate::services::database::{Log, Operation}; use crate::services::helpers::{println_stage_heading, println_step_heading}; use crate::services::satp_helper::{ create_ack_error_message, create_assign_asset_request, create_create_asset_request, create_extinguish_request, create_perform_lock_request, get_request_id_from_transfer_proposal_receipt, log_request_in_local_satp_db, - log_request_in_remote_satp_db, + log_request_in_remote_satp_db, log_request, }; use super::helpers::get_driver; @@ -61,8 +63,10 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { + let step_id = "1.1".to_string(); + println_stage_heading("1".to_string()); - println_step_heading("1.1".to_string()); + println_step_heading(step_id.clone()); println!( "Got a TransferProposalClaimsRequest from {:?} - {:?}", request.remote_addr(), @@ -74,26 +78,21 @@ impl Satp for SatpService { get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); let conf = self.config_lock.read().await; - match log_request_in_remote_satp_db( - &request_id, - &transfer_proposal_claims_request, - conf.clone(), - ) { - Ok(_) => { - println!("Successfully stored TransferProposalClaimsRequest in remote satp_db with request_id: {}", request_id); - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing TransferProposalClaimsRequest in remote satp_db for request_id" - .to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } + let log = Log { + timestamp: Utc::now().naive_utc().to_string(), + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_proposal_claims_request.clone()).unwrap(), + step_id: step_id.clone(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: transfer_proposal_claims_request.clone().sender_gateway_network_id, + received: true, + details: None, + }; + log_request(log); match process_transfer_proposal_claims_request( - transfer_proposal_claims_request, + transfer_proposal_claims_request.clone(), conf.clone(), ) { Ok(ack) => { @@ -102,11 +101,35 @@ impl Satp for SatpService { "Sending Ack of transfer proposal claims request back: {:?}\n", reply ); + let log = Log { + timestamp: Utc::now().naive_utc().to_string(), + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_proposal_claims_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Done, + network_id: "todo_network_id".to_string(), + gateway_id: transfer_proposal_claims_request.clone().sender_gateway_network_id, + received: true, + details: None, + }; + log_request(log); reply } Err(e) => { let error_message = "Transfer proposal claims failed.".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); + let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); + let log = Log { + timestamp: Utc::now().naive_utc().to_string(), + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_proposal_claims_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Failed, + network_id: "todo_network_id".to_string(), + gateway_id: transfer_proposal_claims_request.clone().sender_gateway_network_id, + received: true, + details: Some(error_message), + }; + log_request(log); reply } } @@ -678,6 +701,20 @@ pub fn process_transfer_proposal_claims_request( println!("The transfer proposal claims request is valid\n"); let transfer_proposal_receipt_request = create_transfer_proposal_receipt_request(transfer_proposal_claims_request.clone()); + + let log = Log { + timestamp: Utc::now().naive_utc().to_string(), + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_proposal_claims_request.clone()).unwrap(), + step_id: "1.1".to_string(), + operation: Operation::Exec, + network_id: "todo_network_id".to_string(), + gateway_id: transfer_proposal_claims_request.clone().sender_gateway_network_id, + received: true, + details: None, + }; + log_request(log); + match send_transfer_proposal_receipt_request(transfer_proposal_receipt_request, conf) { Ok(ack) => { println!("Ack transfer proposal claims request."); @@ -1117,13 +1154,13 @@ fn send_transfer_proposal_receipt_request( get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); spawn_send_transfer_proposal_receipt_request( - transfer_proposal_receipt_request, + transfer_proposal_receipt_request.clone(), relay_host, relay_port, use_tls, - tlsca_cert_path, - conf, + tlsca_cert_path ); + let reply = Ack { status: ack::Status::Ok as i32, request_id: request_id.to_string(), @@ -1224,8 +1261,7 @@ fn send_lock_assertion_broadcast_request( relay_host, relay_port, use_tls, - tlsca_cert_path, - conf, + tlsca_cert_path ); let reply = Ack { status: ack::Status::Ok as i32, From 64ce8b382615a064d8696ead8c40509609dcbab0 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 30 Oct 2023 17:55:31 +0000 Subject: [PATCH 45/59] feat: log statements are stored in sqlite db --- ...est_weaver-fabric-fabric-data-sharing.yaml | 1044 - package-lock.json | 17060 ++++++++++++++++ weaver/core/relay/Cargo.lock | 131 +- weaver/core/relay/Cargo.toml | 10 +- weaver/core/relay/docs/README.md | 17 + weaver/core/relay/src/main.rs | 12 + weaver/core/relay/src/services/database.rs | 97 - weaver/core/relay/src/services/logger.rs | 94 + weaver/core/relay/src/services/mod.rs | 2 +- weaver/core/relay/src/services/satp_helper.rs | 70 +- .../core/relay/src/services/satp_service.rs | 46 +- 11 files changed, 17345 insertions(+), 1238 deletions(-) delete mode 100644 .github/workflows/test_weaver-fabric-fabric-data-sharing.yaml create mode 100644 package-lock.json delete mode 100644 weaver/core/relay/src/services/database.rs create mode 100644 weaver/core/relay/src/services/logger.rs diff --git a/.github/workflows/test_weaver-fabric-fabric-data-sharing.yaml b/.github/workflows/test_weaver-fabric-fabric-data-sharing.yaml deleted file mode 100644 index fa84bac89f..0000000000 --- a/.github/workflows/test_weaver-fabric-fabric-data-sharing.yaml +++ /dev/null @@ -1,1044 +0,0 @@ -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: CC-BY-4.0 - -# This is a basic workflow to help you get started with Actions - -name: Test Data Sharing - -# Controls when the workflow will run -on: - # Triggers the workflow on push or pull request events but only for the main branch - push: - branches: [ main ] - pull_request: - branches: [ main ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - fabric-fabric-data-sharing: - if: ${{ false }} - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3.5.2 - - - name: Set up JDK 8 - uses: actions/setup-java@v3.11.0 - with: - java-version: '8' - distribution: 'adopt' - - - name: Set up Go - uses: actions/setup-go@v4.0.0 - with: - go-version: '1.20.2' - - - name: Use Node.js 14.x - uses: actions/setup-node@v3.6.0 - with: - node-version: 14.x - - # CORDA NETWORK - - name: Generate github.properties - run: | - echo "Using ${GITHUB_ACTOR} user." - echo "username=${GITHUB_ACTOR}" >> github.properties - echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.properties - echo "url=https://maven.pkg.github.com/${GITHUB_ACTOR}/cacti" >> github.properties - - echo "Using ${GITHUB_ACTOR} user." - echo "username=${GITHUB_ACTOR}" >> github.main.properties - echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.main.properties - echo "url=https://maven.pkg.github.com/hyperledger/cacti" >> github.main.properties - - ./scripts/get-cordapps.sh || mv github.main.properties github.properties - - cat github.properties - working-directory: weaver/tests/network-setups/corda - - - name: Start Corda Network - run: | - sed -i "/docker logs corda_partya_1 -f/"' s/^/#/' "scripts/start-nodes.sh" - make start &> corda-net.out & - working-directory: weaver/tests/network-setups/corda - - # FABRIC NETWORK - - name: Start Fabric Network - run: make start-interop PROFILE='2-nodes' - working-directory: weaver/tests/network-setups/fabric/dev - - - name: Corda Network logs - run: | - cat tests/network-setups/corda/corda-net.out - docker logs corda_partya_1 - working-directory: weaver - - # RELAY - - name: Edit Relay docker compose - run: make convert-compose-method2 - working-directory: weaver/core/relay - - - name: Start Relay for network1 - run: make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1' - working-directory: weaver/core/relay - - - name: Start Relay for network2 - run: make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2' - working-directory: weaver/core/relay - - - name: Start Relay for Corda_Network - run: make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda' - working-directory: weaver/core/relay - - - name: Start Relay for Corda_Network2 - run: make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.corda2' - working-directory: weaver/core/relay - - # FABRIC DRIVER - - name: Setup Fabric Driver .env - run: | - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet-envs/.env.n1 - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet-envs/.env.n2 - working-directory: weaver/core/drivers/fabric-driver - - - name: Start Fabric Driver for network1 - run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2) - working-directory: weaver/core/drivers/fabric-driver - - - name: Start Fabric Driver for network2 - run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2) - working-directory: weaver/core/drivers/fabric-driver - - # IIN AGENT - - name: Setup Fabric IIN Env - run: | - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n1.org1 - sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n1.org1 - sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n1.org1 - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n1.org2 - sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n1.org2 - sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n1.org2 - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n2.org1 - sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n2.org1 - sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n2.org1 - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n2.org2 - sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n2.org2 - sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n2.org2 - working-directory: weaver/core/identity-management/iin-agent - - - name: Start Fabric IIN Agent for network1 - run: | - make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2) - make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2) - working-directory: weaver/core/identity-management/iin-agent - - - name: Start Fabric IIN Agent for network2 - run: | - make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2) - make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2) - working-directory: weaver/core/identity-management/iin-agent - - # CORDA DRIVER - - name: Start Corda Driver - run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda' - working-directory: weaver/core/drivers/corda-driver - - - name: Start Corda_Network2 Driver - run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.corda2' - working-directory: weaver/core/drivers/corda-driver - - # FABRIC CLI - - name: Setup Fabric CLI .npmrc - run: | - cp .npmrc.template .npmrc - sed -i "s//${{ secrets.GITHUB_TOKEN }}/g" .npmrc - cat .npmrc - working-directory: weaver/samples/fabric/fabric-cli - - name: Build Fabric CLI - run: | - npm install --global yarn - make build - working-directory: weaver/samples/fabric/fabric-cli - - name: Setup Fabric CLI Config - run: | - echo ${GITHUB_WORKSPACE} - cp config.template.json config.json - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" config.json - working-directory: weaver/samples/fabric/fabric-cli - - name: Setup Fabric CLI ENV - run: | - echo ${GITHUB_WORKSPACE} - cp .env.template .env - sed -i "s/CHAINCODE_PATH=.*/CHAINCODE_PATH=\.\/chaincode\.json/g" .env - ./bin/fabric-cli env set MEMBER_CREDENTIAL_FOLDER ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/src/data/credentials_docker - ./bin/fabric-cli env set CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/config.json - cat .env - working-directory: weaver/samples/fabric/fabric-cli - - - name: Fabric CLI Configure ALL - run: ./bin/fabric-cli configure all network1 network2 --num-orgs=2 - working-directory: weaver/samples/fabric/fabric-cli - - - name: Fabric Sync Membership using IIN Agent - run: | - ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 - sleep 30 - docker logs iin-agent-Org1MSP-network1 - docker logs iin-agent-Org1MSP-network2 - ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 - sleep 30 - docker logs iin-agent-Org1MSP-network1 - docker logs iin-agent-Org1MSP-network2 - working-directory: weaver/samples/fabric/fabric-cli - - # CORDA CLIENT - - name: Corda CLI Initialize Vault - run: make initialise-vault-docker - working-directory: weaver/samples/corda/corda-simple-application - - - name: Data Transfer Corda Client Tests - run: | - COUNT=0 - TOTAL=8 - - # CORDA-CORDA2 - ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-corda2:9082/Corda_Network2/corda_network2_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H 1> tmp.out - cat tmp.out | grep "SimpleState(key=H, value=\[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./clients/build/install/clients/bin/clients get-state H 1> tmp.out - cat tmp.out | grep "SimpleState(key=H, value=\[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # CORDA2-CORDA - - NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C 1> tmp.out - cat tmp.out | grep "SimpleState(key=C, value=\[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state C 1> tmp.out - cat tmp.out | grep "SimpleState(key=C, value=\[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # CORDA - FABRIC1 - ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network1:9080/network1/mychannel:simplestate:Read:a 1> tmp.out - cat tmp.out | grep "SimpleState(key=a, value=Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./clients/build/install/clients/bin/clients get-state a 1> tmp.out - cat tmp.out | grep "SimpleState(key=a, value=Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # CORDA - FABRIC2 - ./clients/build/install/clients/bin/clients request-state localhost:9081 relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus 1> tmp.out - cat tmp.out | grep "SimpleState(key=Arcturus, value=17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./clients/build/install/clients/bin/clients get-state Arcturus 1> tmp.out - cat tmp.out | grep "SimpleState(key=Arcturus, value=17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # RESULT - echo "Passed $COUNT/$TOTAL Tests." - - if [ $COUNT == $TOTAL ]; then - exit 0 - else - exit 1 - fi - working-directory: weaver/samples/corda/corda-simple-application - - # FABRIC CLI - - name: Data Transfer Fabric CLI Tests - run: | - COUNT=0 - TOTAL=12 - - # FABRIC2 - FABRIC1 - cp chaincode.json.template chaincode.json - ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP relay-network1:9080/network1/mychannel:simplestate:Read:a &> tmp.out - tail -n 1 tmp.out | grep "Args: a, Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["a"]' --local-network=network2 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC1 - FABRIC2 - sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"Arcturus\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus &> tmp.out - tail -n 1 tmp.out | grep "Args: Arcturus, 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC2 - FABRIC1 - CONFIDENTIAL - sed -i "s/\"args\"\: \[\"Arcturus\"/\"args\"\: \[\"b\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --e2e-confidentiality=true relay-network1:9080/network1/mychannel:simplestate:Read:b &> tmp.out - tail -n 1 tmp.out | grep "Args: b, Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["b"]' --local-network=network2 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC1 - FABRIC2 - CONFIDENTIAL - sed -i "s/\"args\"\: \[\"b\"/\"args\"\: \[\"Betelgeuse\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --e2e-confidentiality=true relay-network2:9083/network2/mychannel:simplestate:Read:Betelgeuse &> tmp.out - tail -n 1 tmp.out | grep "Args: Betelgeuse, 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["Betelgeuse"]' --local-network=network1 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["Arcturus"]' --local-network=network1 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC1 - CORDA - cp chaincode.json.template chaincode.json - sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"H\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true &> tmp.out - tail -n 1 tmp.out | grep "Args: H, \[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["H"]' --local-network=network1 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: \[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC2 - CORDA - cp chaincode.json.template chaincode.json - sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"C\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP relay-corda:9081/Corda_Network/corda_partya_1:10003#com.cordaSimpleApplication.flow.GetStateByKey:C --debug=true &> tmp.out - tail -n 1 tmp.out | grep "Args: C, \[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["C"]' --local-network=network2 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: \[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - - # RESULT - echo "Passed $COUNT/$TOTAL Tests." - - if [ $COUNT == $TOTAL ]; then - exit 0 - else - exit 1 - fi - working-directory: weaver/samples/fabric/fabric-cli - - - name: DEBUG Logs - corda partya - if: failure() - run: docker logs corda_partya_1 - - - name: DEBUG Logs - corda network2 partya - if: failure() - run: docker logs corda_network2_partya_1 - - - name: DEBUG Logs - fabric n1 relay - if: failure() - run: docker logs relay-network1 - - - name: DEBUG Logs - fabric n2 relay - if: failure() - run: docker logs relay-network2 - - - name: DEBUG Logs - corda relay - if: failure() - run: docker logs relay-corda - - - name: DEBUG Logs - corda2 relay - if: failure() - run: docker logs relay-corda2 - - - name: DEBUG Logs - fabric n1 driver - if: failure() - run: docker logs driver-fabric-network1 - - - name: DEBUG Logs - fabric n2 driver - if: failure() - run: docker logs driver-fabric-network2 - - - name: DEBUG Logs - corda driver - if: failure() - run: docker logs driver-corda-Corda_Network - - - name: DEBUG Logs - corda2 driver - if: failure() - run: docker logs driver-corda-Corda_Network2 - - fabric-fabric-data-sharing-docker-local: - # if: ${{ false }} - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3.5.2 - - - name: Install Yarn - run: npm install -g yarn - - - name: Install Envsubst - run: apt-get update && apt-get install gettext-base - - - name: Set up JDK 8 - uses: actions/setup-java@v3.11.0 - with: - java-version: '8' - distribution: 'adopt' - - - name: Set up Go - uses: actions/setup-go@v4.0.0 - with: - go-version: '1.20.2' - - - name: Use Node.js 14.x - uses: actions/setup-node@v3.6.0 - with: - node-version: 14.x - - - name: Use Protoc 3.15 - run: | - curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip - unzip protoc-3.15.6-linux-x86_64.zip -d protoc - go install google.golang.org/protobuf/cmd/protoc-gen-go@latest - go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest - - # PROTOS - - name: Build GO Protos - run: | - export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" - make build - working-directory: weaver/common/protos-go - - # PROTOS - - name: Build JS Protos - run: | - export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" - make build - working-directory: weaver/common/protos-js - - - name: Build Java Protos - run: make build - working-directory: weaver/common/protos-java-kt - - # Build Dependencies - - name: Build Fabric Interop SDK - run: make build-local - working-directory: weaver/sdks/fabric/interoperation-node-sdk - - - name: Build Fabric CLI - run: make build-local - working-directory: weaver/samples/fabric/fabric-cli - - - name: Build Relay - run: make build-server-local - working-directory: weaver/core/relay - - - name: Build Fabric Driver - run: make build-image-local - working-directory: weaver/core/drivers/fabric-driver - - - name: Build IIN Agent - run: make build-image-local - working-directory: weaver/core/identity-management/iin-agent - - # FABRIC NETWORK - - name: Start Fabric Network - run: make start-interop-local PROFILE='2-nodes' - working-directory: weaver/tests/network-setups/fabric/dev - - # RELAY - - name: Edit Relay docker compose - run: make convert-compose-method2 - working-directory: weaver/core/relay - - - name: Start Relay for network1 - run: | - sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-relay-server#g" docker/testnet-envs/.env.n1 - make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n1' - working-directory: weaver/core/relay - - - name: Start Relay for network2 - run: | - sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-relay-server#g" docker/testnet-envs/.env.n2 - make start-server COMPOSE_ARG='--env-file docker/testnet-envs/.env.n2' - working-directory: weaver/core/relay - - # FABRIC DRIVER - - name: Setup Fabric Driver .env - run: | - sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-driver-fabric#g" docker-testnet-envs/.env.n1 - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet-envs/.env.n1 - sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-driver-fabric#g" docker-testnet-envs/.env.n2 - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet-envs/.env.n2 - working-directory: weaver/core/drivers/fabric-driver - - - name: Start Fabric Driver for network1 - run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n1' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n1 | cut -d '=' -f 2) - working-directory: weaver/core/drivers/fabric-driver - - - name: Start Fabric Driver for network2 - run: make deploy COMPOSE_ARG='--env-file docker-testnet-envs/.env.n2' NETWORK_NAME=$(grep NETWORK_NAME docker-testnet-envs/.env.n2 | cut -d '=' -f 2) - working-directory: weaver/core/drivers/fabric-driver - - # IIN AGENT - - name: Setup Fabric IIN Env - run: | - sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-iin-agent#g" docker-testnet/envs/.env.n1.org1 - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n1.org1 - sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n1.org1 - sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n1.org1 - sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-iin-agent#g" docker-testnet/envs/.env.n1.org2 - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n1.org2 - sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n1.org2 - sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n1.org2 - sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-iin-agent#g" docker-testnet/envs/.env.n2.org1 - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n2.org1 - sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n2.org1 - sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n2.org1 - sed -i "s#^DOCKER_IMAGE_NAME=.*#DOCKER_IMAGE_NAME=cacti-weaver-iin-agent#g" docker-testnet/envs/.env.n2.org2 - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" docker-testnet/envs/.env.n2.org2 - sed -i "s#^AUTO_SYNC=true#AUTO_SYNC=false#g" docker-testnet/envs/.env.n2.org2 - sed -i "s#^DNS_CONFIG_PATH=.*#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig-2-nodes.json#g" docker-testnet/envs/.env.n2.org2 - working-directory: weaver/core/identity-management/iin-agent - - - name: Start Fabric IIN Agent for network1 - run: | - make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org1 | cut -d '=' -f 2) - make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n1.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n1.org2 | cut -d '=' -f 2) - working-directory: weaver/core/identity-management/iin-agent - - - name: Start Fabric IIN Agent for network2 - run: | - make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org1' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org1 | cut -d '=' -f 2) - make deploy COMPOSE_ARG='--env-file docker-testnet/envs/.env.n2.org2' DLT_SPECIFIC_DIR=$(grep DLT_SPECIFIC_DIR docker-testnet/envs/.env.n2.org2 | cut -d '=' -f 2) - working-directory: weaver/core/identity-management/iin-agent - - # FABRIC CLI - - name: Setup Fabric CLI Config - run: | - echo ${GITHUB_WORKSPACE} - cp config.template.json config.json - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" config.json - working-directory: weaver/samples/fabric/fabric-cli - - name: Setup Fabric CLI ENV - run: | - echo ${GITHUB_WORKSPACE} - cp .env.template .env - sed -i "s/CHAINCODE_PATH=.*/CHAINCODE_PATH=\.\/chaincode\.json/g" .env - ./bin/fabric-cli env set MEMBER_CREDENTIAL_FOLDER ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/src/data/credentials_docker - ./bin/fabric-cli env set CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/config.json - cat .env - working-directory: weaver/samples/fabric/fabric-cli - - - name: Fabric CLI Configure ALL - run: ./bin/fabric-cli configure all network1 network2 --num-orgs=2 - working-directory: weaver/samples/fabric/fabric-cli - - - name: Fabric Sync Membership using IIN Agent - run: | - ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 - sleep 30 - docker logs iin-agent-Org1MSP-network1 - docker logs iin-agent-Org1MSP-network2 - ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 - sleep 30 - docker logs iin-agent-Org1MSP-network1 - docker logs iin-agent-Org1MSP-network2 - working-directory: weaver/samples/fabric/fabric-cli - - # FABRIC CLI - - name: Data Transfer Fabric CLI Tests - run: | - COUNT=0 - TOTAL=8 - - # FABRIC2 - FABRIC1 - cp chaincode.json.template chaincode.json - ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP relay-network1:9080/network1/mychannel:simplestate:Read:a &> tmp.out - tail -n 1 tmp.out | grep "Args: a, Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["a"]' --local-network=network2 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC1 - FABRIC2 - sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"Arcturus\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP relay-network2:9083/network2/mychannel:simplestate:Read:Arcturus &> tmp.out - tail -n 1 tmp.out | grep "Args: Arcturus, 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["Arcturus"]' --local-network=network1 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC2 - FABRIC1 - CONFIDENTIAL - sed -i "s/\"args\"\: \[\"Arcturus\"/\"args\"\: \[\"b\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --e2e-confidentiality=true relay-network1:9080/network1/mychannel:simplestate:Read:b &> tmp.out - tail -n 1 tmp.out | grep "Args: b, Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["b"]' --local-network=network2 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC1 - FABRIC2 - CONFIDENTIAL - sed -i "s/\"args\"\: \[\"b\"/\"args\"\: \[\"Betelgeuse\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --e2e-confidentiality=true relay-network2:9083/network2/mychannel:simplestate:Read:Betelgeuse &> tmp.out - tail -n 1 tmp.out | grep "Args: Betelgeuse, 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["Betelgeuse"]' --local-network=network1 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # RESULT - echo "Passed $COUNT/$TOTAL Tests." - - if [ $COUNT == $TOTAL ]; then - exit 0 - else - exit 1 - fi - working-directory: weaver/samples/fabric/fabric-cli - - - name: DEBUG Logs - fabric n1 relay - if: failure() - run: docker logs relay-network1 - - - name: DEBUG Logs - fabric n2 relay - if: failure() - run: docker logs relay-network2 - - - name: DEBUG Logs - fabric n1 driver - if: failure() - run: docker logs driver-fabric-network1 - - - name: DEBUG Logs - fabric n2 driver - if: failure() - run: docker logs driver-fabric-network2 - - fabric-fabric-data-sharing-local: - # if: ${{ false }} - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3.5.2 - - - name: Set up JDK 8 - uses: actions/setup-java@v3.11.0 - with: - java-version: '8' - distribution: 'adopt' - - - name: Set up Go - uses: actions/setup-go@v4.0.0 - with: - go-version: '1.20.2' - - - name: Use Node.js 16.x - uses: actions/setup-node@v3.6.0 - with: - node-version: 16.x - - - name: Install RUST Toolchain minimal stable with clippy and rustfmt - uses: actions-rs/toolchain@v1.0.6 - with: - profile: minimal - toolchain: stable - components: rustfmt, clippy - - - name: Get Latest Relay Dependencies - run: | - make protos-local - cargo update -p nom - cargo update -p lexical-core - working-directory: weaver/core/relay - - - name: Use Protoc 3.15 - run: | - curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v3.15.6/protoc-3.15.6-linux-x86_64.zip - unzip protoc-3.15.6-linux-x86_64.zip -d protoc - go install google.golang.org/protobuf/cmd/protoc-gen-go@latest - go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest - - # PROTOS - - name: Build GO Protos - run: | - export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" - make build - working-directory: weaver/common/protos-go - - # PROTOS - - name: Build JS Protos - run: | - export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" - make build - working-directory: weaver/common/protos-js - - - name: Build Java Protos - run: make build - working-directory: weaver/common/protos-java-kt - - # Build Dependencies - - name: Build Corda Interop App - run: make build-local - working-directory: weaver/core/network/corda-interop-app - - - name: Build Corda Interop SDK - run: make build - working-directory: weaver/sdks/corda - - - name: Build Corda SimpleApplication - run: make build-local - working-directory: weaver/samples/corda/corda-simple-application - - - name: Build Fabric Interop SDK - run: make build-local - working-directory: weaver/sdks/fabric/interoperation-node-sdk - - - name: Build Fabric CLI - run: make build-local - working-directory: weaver/samples/fabric/fabric-cli - - - name: Build Relay - run: make - working-directory: weaver/core/relay - - - name: Build Fabric Driver - run: make build-local - working-directory: weaver/core/drivers/fabric-driver - - - name: Build Corda Driver - run: make build-local - working-directory: weaver/core/drivers/corda-driver - - - name: Build IIN Agent - run: make build-local - working-directory: weaver/core/identity-management/iin-agent - - # CORDA NETWORK - - name: Start Corda Network - run: | - sed -i "/docker logs corda_partya_1 -f/"' s/^/#/' "scripts/start-nodes.sh" - make start-local &> corda-net.out & - working-directory: weaver/tests/network-setups/corda - - # FABRIC NETWORK - - - name: Start Fabric Network - run: make start-interop-local - working-directory: weaver/tests/network-setups/fabric/dev - - - name: Corda Network logs - run: | - cat tests/network-setups/corda/corda-net.out - docker logs corda_partya_1 - working-directory: weaver - - # RELAY - - name: Start Relay for network1 - run: RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server &> relay-n1.out & - working-directory: weaver/core/relay - - - name: Start Relay for network2 - run: RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server &> relay-n2.out & - working-directory: weaver/core/relay - - - name: Start Relay for Corda_Network - run: RELAY_CONFIG=config/Corda_Relay.toml cargo run --bin server &> relay-corda.out & - working-directory: weaver/core/relay - - - name: Start Relay for Corda_Network2 - run: RELAY_CONFIG=config/Corda_Relay2.toml cargo run --bin server &> relay-corda2.out & - working-directory: weaver/core/relay - - # FABRIC DRIVER - - name: Setup Fabric Driver .env - run: | - cp .env.template .env - CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json - sed -i "s#path_to_connection_profile#${CCP_PATH}#g" .env - working-directory: weaver/core/drivers/fabric-driver - - - name: Start Fabric Driver for network1 - run: npm run dev &> fdriver-n1.out & - working-directory: weaver/core/drivers/fabric-driver - - - name: Start Fabric Driver for network2 - run: CONNECTION_PROFILE=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev &> fdriver-n2.out & - working-directory: weaver/core/drivers/fabric-driver - - # IIN AGENT - - name: Setup Fabric IIN Config - run: | - # FABRIC CONFIG - cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n1.json - CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json - sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n1.json - cat src/fabric-ledger/config-n1.json - cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n2.json - CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json - sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n2.json - cat src/fabric-ledger/config-n2.json - # DNS CONFIG - sed -i "s#iin-agent-Org1MSP-network1#localhost#g" docker-testnet/configs/dnsconfig.json - sed -i "s#iin-agent-Org1MSP-network2#localhost#g" docker-testnet/configs/dnsconfig.json - cat docker-testnet/configs/dnsconfig.json - working-directory: weaver/core/identity-management/iin-agent - - - name: Setup Fabric IIN Env - run: | - cp .env.template .env - sed -i "s##Org1MSP#g" .env - sed -i "s#^DLT_TYPE=.*#DLT_TYPE=fabric#g" .env - sed -i "s##interop#g" .env - sed -i "s#^DNS_CONFIG_PATH=#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig.json#g" .env - sed -i "s#^SECURITY_DOMAIN_CONFIG_PATH=#SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json#g" .env - sed -i "s#^CONFIG_PATH=#CONFIG_PATH=./src/fabric-ledger/config-n1.json#g" .env - sed -i "s#^AUTO_SYNC=#AUTO_SYNC=false#g" .env - cat .env - working-directory: weaver/core/identity-management/iin-agent - - - name: Start Fabric IIN Agent for network1 - run: npm run dev &> iinagent-n1.out & - working-directory: weaver/core/identity-management/iin-agent - - - name: Start Fabric IIN Agent for network2 - run: IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2.json npm run dev &> iinagent-n2.out & - working-directory: weaver/core/identity-management/iin-agent - - # CORDA DRIVER - - name: Start Corda_Network Driver - run: ./build/install/driver-corda/bin/driver-corda &> corda-driver.out & - working-directory: weaver/core/drivers/corda-driver - - - name: Start Corda_Network2 Driver - run: DRIVER_PORT=9098 ./build/install/driver-corda/bin/driver-corda &> corda2-driver.out & - working-directory: weaver/core/drivers/corda-driver - - # FABRIC CLI - - name: Setup Fabric CLI Config - run: | - echo ${GITHUB_WORKSPACE} - cp config.template.json config.json - sed -i "s##${GITHUB_WORKSPACE}/weaver#g" config.json - working-directory: weaver/samples/fabric/fabric-cli - - name: Setup Fabric CLI ENV - run: | - echo ${GITHUB_WORKSPACE} - cp .env.template .env - sed -i "s/CHAINCODE_PATH=.*/CHAINCODE_PATH=\.\/chaincode\.json/g" .env - ./bin/fabric-cli env set MEMBER_CREDENTIAL_FOLDER ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/src/data/credentials - ./bin/fabric-cli env set CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/config.json - cat .env - cp chaincode.json.template chaincode.json - working-directory: weaver/samples/fabric/fabric-cli - - - name: Fabric CLI Configure ALL - run: ./bin/fabric-cli configure all network1 network2 - working-directory: weaver/samples/fabric/fabric-cli - - - name: Fabric Sync Membership using IIN Agent - run: | - ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 - sleep 10 - tail -10 ../../../core/identity-management/iin-agent/iinagent-n1.out - ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 - sleep 10 - tail -10 ../../../core/identity-management/iin-agent/iinagent-n2.out - working-directory: weaver/samples/fabric/fabric-cli - - # CORDA CLIENT - - name: Corda CLI Initialize Vault - run: make initialise-vault - working-directory: weaver/samples/corda/corda-simple-application - - - name: Data Transfer Corda Client Tests - run: | - COUNT=0 - TOTAL=8 - - # CORDA-CORDA2 - ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9082/Corda_Network2/localhost:30006#com.cordaSimpleApplication.flow.GetStateByKey:H 1> tmp.out - cat tmp.out | grep "SimpleState(key=H, value=\[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./clients/build/install/clients/bin/clients get-state H 1> tmp.out - cat tmp.out | grep "SimpleState(key=H, value=\[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # CORDA2-CORDA - - NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients request-state localhost:9082 localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C 1> tmp.out - cat tmp.out | grep "SimpleState(key=C, value=\[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - NETWORK_NAME=Corda_Network2 CORDA_PORT=30006 ./clients/build/install/clients/bin/clients get-state C 1> tmp.out - cat tmp.out | grep "SimpleState(key=C, value=\[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # CORDA - FABRIC1 - ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9080/network1/mychannel:simplestate:Read:a 1> tmp.out - cat tmp.out | grep "SimpleState(key=a, value=Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./clients/build/install/clients/bin/clients get-state a 1> tmp.out - cat tmp.out | grep "SimpleState(key=a, value=Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # CORDA - FABRIC2 - ./clients/build/install/clients/bin/clients request-state localhost:9081 localhost:9083/network2/mychannel:simplestate:Read:Arcturus 1> tmp.out - cat tmp.out | grep "SimpleState(key=Arcturus, value=17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./clients/build/install/clients/bin/clients get-state Arcturus 1> tmp.out - cat tmp.out | grep "SimpleState(key=Arcturus, value=17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # RESULT - echo "Passed $COUNT/$TOTAL Tests." - - if [ $COUNT == $TOTAL ]; then - exit 0 - else - exit 1 - fi - working-directory: weaver/samples/corda/corda-simple-application - - # FABRIC CLI - - name: Data Transfer Fabric CLI Tests - run: | - COUNT=0 - TOTAL=12 - - # FABRIC2 - FABRIC1 - cp chaincode.json.template chaincode.json - ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP localhost:9080/network1/mychannel:simplestate:Read:a &> tmp.out - tail -n 1 tmp.out | grep "Args: a, Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["a"]' --local-network=network2 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: Arcturus" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC2 - FABRIC1 - CONFIDENTIAL - sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"b\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network2 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9080/network1/mychannel:simplestate:Read:b &> tmp.out - tail -n 1 tmp.out | grep "Args: b, Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["b"]' --local-network=network2 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: Betelgeuse" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC1 - FABRIC2 - sed -i "s/\"args\"\: \[\"b\"/\"args\"\: \[\"Arcturus\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP localhost:9083/network2/mychannel:simplestate:Read:Arcturus &> tmp.out - tail -n 1 tmp.out | grep "Args: Arcturus, 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["Arcturus"]' --local-network=network1 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: 17.671" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC1 - FABRIC2 - CONFIDENTIAL - sed -i "s/\"args\"\: \[\"Arcturus\"/\"args\"\: \[\"Betelgeuse\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network1 --requesting-org=Org1MSP --e2e-confidentiality=true localhost:9083/network2/mychannel:simplestate:Read:Betelgeuse &> tmp.out - tail -n 1 tmp.out | grep "Args: Betelgeuse, 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["Betelgeuse"]' --local-network=network1 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: 617.1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC1 - CORDA - cp chaincode.json.template chaincode.json - sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"H\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network1 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:H --debug=true &> tmp.out - tail -n 1 tmp.out | grep "Args: H, \[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["H"]' --local-network=network1 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: \[SimpleState(key=H, value=1" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # FABRIC2 - CORDA - cp chaincode.json.template chaincode.json - sed -i "s/\"args\"\: \[\"a\"/\"args\"\: \[\"C\"/g" chaincode.json - ./bin/fabric-cli interop --local-network=network2 --sign=true --requesting-org=Org1MSP localhost:9081/Corda_Network/localhost:10006#com.cordaSimpleApplication.flow.GetStateByKey:C --debug=true --debug=true &> tmp.out - tail -n 1 tmp.out | grep "Args: C, \[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query mychannel simplestate read '["C"]' --local-network=network2 &> tmp.out - tail -n 1 tmp.out | grep "Result from network query: \[SimpleState(key=C, value=20" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - - # RESULT - echo "Passed $COUNT/$TOTAL Tests." - - if [ $COUNT == $TOTAL ]; then - exit 0 - else - exit 1 - fi - working-directory: weaver/samples/fabric/fabric-cli - - - name: DEBUG Logs - corda partya - if: failure() - run: docker logs corda_partya_1 - - - name: DEBUG Logs - corda network2 partya - if: failure() - run: docker logs corda_network2_partya_1 - - - name: DEBUG Logs - fabric n1 relay - if: failure() - run: cat weaver/core/relay/relay-n1.out - - - name: DEBUG Logs - fabric n2 relay - if: failure() - run: cat weaver/core/relay/relay-n2.out - - - name: DEBUG Logs - corda relay - if: failure() - run: cat weaver/core/relay/relay-corda.out - - - name: DEBUG Logs - corda2 relay - if: failure() - run: cat weaver/core/relay/relay-corda2.out - - - name: DEBUG Logs - fabric n1 driver - if: failure() - run: cat weaver/core/drivers/fabric-driver/fdriver-n1.out - - - name: DEBUG Logs - fabric n2 driver - if: failure() - run: cat weaver/core/drivers/fabric-driver/fdriver-n2.out - - - name: DEBUG Logs - corda driver - if: failure() - run: cat weaver/core/drivers/corda-driver/corda-driver.out - - - name: DEBUG Logs - corda2 driver - if: failure() - run: cat weaver/core/drivers/corda-driver/corda2-driver.out diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..a0114f0a83 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,17060 @@ +{ + "name": "@hyperledger/cactus", + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@adraffy/ens-normalize": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", + "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^1.9.0" + } + }, + "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, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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, + "requires": { + "color-name": "1.1.3" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/compat-data": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", + "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "dev": true + }, + "@babel/core": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "dev": true, + "requires": { + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", + "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "dev": true + }, + "@babel/helpers": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" + } + }, + "@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^1.9.0" + } + }, + "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, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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, + "requires": { + "color-name": "1.1.3" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/runtime": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/traverse": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@commitlint/cli": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.7.1.tgz", + "integrity": "sha512-BCm/AT06SNCQtvFv921iNhudOHuY16LswT0R3OeolVGLk8oP+Rk9TfQfgjH7QPMjhvp76bNqGFEcpKojxUNW1g==", + "dev": true, + "requires": { + "@commitlint/format": "^17.4.4", + "@commitlint/lint": "^17.7.0", + "@commitlint/load": "^17.7.1", + "@commitlint/read": "^17.5.1", + "@commitlint/types": "^17.4.4", + "execa": "^5.0.0", + "lodash.isfunction": "^3.0.9", + "resolve-from": "5.0.0", + "resolve-global": "1.0.0", + "yargs": "^17.0.0" + } + }, + "@commitlint/config-conventional": { + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.7.0.tgz", + "integrity": "sha512-iicqh2o6et+9kWaqsQiEYZzfLbtoWv9uZl8kbI8EGfnc0HeGafQBF7AJ0ylN9D/2kj6txltsdyQs8+2fTMwWEw==", + "dev": true, + "requires": { + "conventional-changelog-conventionalcommits": "^6.1.0" + } + }, + "@commitlint/config-validator": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-17.8.1.tgz", + "integrity": "sha512-UUgUC+sNiiMwkyiuIFR7JG2cfd9t/7MV8VB4TZ+q02ZFkHoduUS4tJGsCBWvBOGD9Btev6IecPMvlWUfJorkEA==", + "dev": true, + "requires": { + "@commitlint/types": "^17.8.1", + "ajv": "^8.11.0" + } + }, + "@commitlint/ensure": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-17.8.1.tgz", + "integrity": "sha512-xjafwKxid8s1K23NFpL8JNo6JnY/ysetKo8kegVM7c8vs+kWLP8VrQq+NbhgVlmCojhEDbzQKp4eRXSjVOGsow==", + "dev": true, + "requires": { + "@commitlint/types": "^17.8.1", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" + } + }, + "@commitlint/execute-rule": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-17.8.1.tgz", + "integrity": "sha512-JHVupQeSdNI6xzA9SqMF+p/JjrHTcrJdI02PwesQIDCIGUrv04hicJgCcws5nzaoZbROapPs0s6zeVHoxpMwFQ==", + "dev": true + }, + "@commitlint/format": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-17.8.1.tgz", + "integrity": "sha512-f3oMTyZ84M9ht7fb93wbCKmWxO5/kKSbwuYvS867duVomoOsgrgljkGGIztmT/srZnaiGbaK8+Wf8Ik2tSr5eg==", + "dev": true, + "requires": { + "@commitlint/types": "^17.8.1", + "chalk": "^4.1.0" + } + }, + "@commitlint/is-ignored": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.8.1.tgz", + "integrity": "sha512-UshMi4Ltb4ZlNn4F7WtSEugFDZmctzFpmbqvpyxD3la510J+PLcnyhf9chs7EryaRFJMdAKwsEKfNK0jL/QM4g==", + "dev": true, + "requires": { + "@commitlint/types": "^17.8.1", + "semver": "7.5.4" + } + }, + "@commitlint/lint": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.8.1.tgz", + "integrity": "sha512-aQUlwIR1/VMv2D4GXSk7PfL5hIaFSfy6hSHV94O8Y27T5q+DlDEgd/cZ4KmVI+MWKzFfCTiTuWqjfRSfdRllCA==", + "dev": true, + "requires": { + "@commitlint/is-ignored": "^17.8.1", + "@commitlint/parse": "^17.8.1", + "@commitlint/rules": "^17.8.1", + "@commitlint/types": "^17.8.1" + } + }, + "@commitlint/load": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.8.1.tgz", + "integrity": "sha512-iF4CL7KDFstP1kpVUkT8K2Wl17h2yx9VaR1ztTc8vzByWWcbO/WaKwxsnCOqow9tVAlzPfo1ywk9m2oJ9ucMqA==", + "dev": true, + "requires": { + "@commitlint/config-validator": "^17.8.1", + "@commitlint/execute-rule": "^17.8.1", + "@commitlint/resolve-extends": "^17.8.1", + "@commitlint/types": "^17.8.1", + "@types/node": "20.5.1", + "chalk": "^4.1.0", + "cosmiconfig": "^8.0.0", + "cosmiconfig-typescript-loader": "^4.0.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0", + "resolve-from": "^5.0.0", + "ts-node": "^10.8.1", + "typescript": "^4.6.4 || ^5.2.2" + }, + "dependencies": { + "@types/node": { + "version": "20.5.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", + "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==", + "dev": true + } + } + }, + "@commitlint/message": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.8.1.tgz", + "integrity": "sha512-6bYL1GUQsD6bLhTH3QQty8pVFoETfFQlMn2Nzmz3AOLqRVfNNtXBaSY0dhZ0dM6A2MEq4+2d7L/2LP8TjqGRkA==", + "dev": true + }, + "@commitlint/parse": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-17.8.1.tgz", + "integrity": "sha512-/wLUickTo0rNpQgWwLPavTm7WbwkZoBy3X8PpkUmlSmQJyWQTj0m6bDjiykMaDt41qcUbfeFfaCvXfiR4EGnfw==", + "dev": true, + "requires": { + "@commitlint/types": "^17.8.1", + "conventional-changelog-angular": "^6.0.0", + "conventional-commits-parser": "^4.0.0" + } + }, + "@commitlint/read": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-17.8.1.tgz", + "integrity": "sha512-Fd55Oaz9irzBESPCdMd8vWWgxsW3OWR99wOntBDHgf9h7Y6OOHjWEdS9Xzen1GFndqgyoaFplQS5y7KZe0kO2w==", + "dev": true, + "requires": { + "@commitlint/top-level": "^17.8.1", + "@commitlint/types": "^17.8.1", + "fs-extra": "^11.0.0", + "git-raw-commits": "^2.0.11", + "minimist": "^1.2.6" + }, + "dependencies": { + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@commitlint/resolve-extends": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.8.1.tgz", + "integrity": "sha512-W/ryRoQ0TSVXqJrx5SGkaYuAaE/BUontL1j1HsKckvM6e5ZaG0M9126zcwL6peKSuIetJi7E87PRQF8O86EW0Q==", + "dev": true, + "requires": { + "@commitlint/config-validator": "^17.8.1", + "@commitlint/types": "^17.8.1", + "import-fresh": "^3.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0", + "resolve-global": "^1.0.0" + } + }, + "@commitlint/rules": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-17.8.1.tgz", + "integrity": "sha512-2b7OdVbN7MTAt9U0vKOYKCDsOvESVXxQmrvuVUZ0rGFMCrCPJWWP1GJ7f0lAypbDAhaGb8zqtdOr47192LBrIA==", + "dev": true, + "requires": { + "@commitlint/ensure": "^17.8.1", + "@commitlint/message": "^17.8.1", + "@commitlint/to-lines": "^17.8.1", + "@commitlint/types": "^17.8.1", + "execa": "^5.0.0" + } + }, + "@commitlint/to-lines": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-17.8.1.tgz", + "integrity": "sha512-LE0jb8CuR/mj6xJyrIk8VLz03OEzXFgLdivBytoooKO5xLt5yalc8Ma5guTWobw998sbR3ogDd+2jed03CFmJA==", + "dev": true + }, + "@commitlint/top-level": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-17.8.1.tgz", + "integrity": "sha512-l6+Z6rrNf5p333SHfEte6r+WkOxGlWK4bLuZKbtf/2TXRN+qhrvn1XE63VhD8Oe9oIHQ7F7W1nG2k/TJFhx2yA==", + "dev": true, + "requires": { + "find-up": "^5.0.0" + }, + "dependencies": { + "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, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "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, + "requires": { + "p-locate": "^5.0.0" + } + }, + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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, + "requires": { + "p-limit": "^3.0.2" + } + } + } + }, + "@commitlint/types": { + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-17.8.1.tgz", + "integrity": "sha512-PXDQXkAmiMEG162Bqdh9ChML/GJZo6vU+7F03ALKDK8zYc6SuAr47LjG7hGYRqUOz+WK0dU7bQ0xzuqFMdxzeQ==", + "dev": true, + "requires": { + "chalk": "^4.1.0" + } + }, + "@cspell/cspell-bundled-dicts": { + "version": "5.21.2", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.21.2.tgz", + "integrity": "sha512-Y5TU6wV/H+RV1VOB32MowiKofBsEZId4x4ReWCyw4KUtJegeljajCfhHwiQaZuvA69E13cJnOMDwi9qozj4kjw==", + "dev": true, + "requires": { + "@cspell/dict-ada": "^2.0.0", + "@cspell/dict-aws": "^2.0.0", + "@cspell/dict-bash": "^2.0.2", + "@cspell/dict-companies": "^2.0.4", + "@cspell/dict-cpp": "^3.1.0", + "@cspell/dict-cryptocurrencies": "^2.0.0", + "@cspell/dict-csharp": "^3.0.1", + "@cspell/dict-css": "^2.0.0", + "@cspell/dict-dart": "^1.1.0", + "@cspell/dict-django": "^2.0.0", + "@cspell/dict-dotnet": "^2.0.1", + "@cspell/dict-elixir": "^2.0.1", + "@cspell/dict-en-gb": "^1.1.33", + "@cspell/dict-en_us": "^2.2.5", + "@cspell/dict-filetypes": "^2.0.1", + "@cspell/dict-fonts": "^2.0.0", + "@cspell/dict-fullstack": "^2.0.5", + "@cspell/dict-git": "^1.0.1", + "@cspell/dict-golang": "^3.0.1", + "@cspell/dict-haskell": "^2.0.0", + "@cspell/dict-html": "^3.0.1", + "@cspell/dict-html-symbol-entities": "^3.0.0", + "@cspell/dict-java": "^2.0.0", + "@cspell/dict-latex": "^2.0.3", + "@cspell/dict-lorem-ipsum": "^2.0.0", + "@cspell/dict-lua": "^2.0.0", + "@cspell/dict-node": "^2.0.1", + "@cspell/dict-npm": "^2.0.3", + "@cspell/dict-php": "^2.0.0", + "@cspell/dict-powershell": "^2.0.0", + "@cspell/dict-public-licenses": "^1.0.4", + "@cspell/dict-python": "^3.0.5", + "@cspell/dict-r": "^1.0.2", + "@cspell/dict-ruby": "^2.0.1", + "@cspell/dict-rust": "^2.0.0", + "@cspell/dict-scala": "^2.0.0", + "@cspell/dict-software-terms": "^2.1.7", + "@cspell/dict-swift": "^1.0.2", + "@cspell/dict-typescript": "^2.0.0", + "@cspell/dict-vue": "^2.0.2" + } + }, + "@cspell/cspell-pipe": { + "version": "5.21.2", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-5.21.2.tgz", + "integrity": "sha512-MN1SXeqqurWYNknbUMPHRFyTvURbO53/1Aw3zEoCeVUSiGbD5rrb1N+t0YDbOphWrkkrJAZk82/2ZBJ2USE/vg==", + "dev": true + }, + "@cspell/cspell-types": { + "version": "5.21.2", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-5.21.2.tgz", + "integrity": "sha512-g2h4qNR6C53IcSM3KR0DZ9gsqp+2FyKD371htJOmSJGmWb4s45QY0hsPr12A2J8/bT+E3uMtHn9KxJeQ7t0SzA==", + "dev": true + }, + "@cspell/dict-ada": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-2.0.1.tgz", + "integrity": "sha512-vopTJ1oHrrFYV5GU55Sr+AzItR78Uj5YbCaspYABmYKlq4NRrcUAUsr4bWgymDcspMIHO7e7IFcj48OKs1fndA==", + "dev": true + }, + "@cspell/dict-aws": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-2.0.0.tgz", + "integrity": "sha512-NKz7pDZ7pwj/b33i3f4WLpC1rOOUMmENwYgftxU+giU2YBeKM2wZbMTSEIzsrel56r0UlQYmdIVlP/B4nnVaoQ==", + "dev": true + }, + "@cspell/dict-bash": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-2.0.4.tgz", + "integrity": "sha512-uK/ehmp5LYrmRH2Gv3nbvdPswpkybJUn34WYKLpeuYHQktmi+pOI1A9uPdBPnSbMDffSvwQlQohIyKawz+X8Ag==", + "dev": true + }, + "@cspell/dict-companies": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-2.0.14.tgz", + "integrity": "sha512-Sq1X29Z05OZ/UNqTwVhf3/WaqvJQy4/S6gS8qYI5AQRX45gVe8CPhNBLmZOTC6z8m716bfQCxa5rRT9YNSdTZg==", + "dev": true + }, + "@cspell/dict-cpp": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-3.2.1.tgz", + "integrity": "sha512-XcmzrKIghqFfrYLLaHtWKOp9rupiuGdc5ODONk+emsq0W5CIc3Abn27IQHwUzxzF+Cm5IfKAIJ5Kpe6hkzm0HQ==", + "dev": true + }, + "@cspell/dict-cryptocurrencies": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-2.0.0.tgz", + "integrity": "sha512-nREysmmfOp7L2YCRAUufQahwD5/Punzb5AZ6eyg4zUamdRWHgBFphb5/9h2flt1vgdUfhc6hZcML21Ci7iXjaA==", + "dev": true + }, + "@cspell/dict-csharp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-3.0.1.tgz", + "integrity": "sha512-xkfQu03F388w4sdVQSSjrVMkxAxpTYB2yW7nw0XYtTjl3L/jBgvTr/j1BTjdFbQhdNf10Lg0Ak1kXOjmHodVqA==", + "dev": true + }, + "@cspell/dict-css": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-2.1.0.tgz", + "integrity": "sha512-glASAELcGhh4Ru0rTQ4G9mTQxSyPwsZOON/5BYflB6Kks8YC8nUvKrtMCoo5W7CPKPfSEa8zUNctFQ1+IUYDHA==", + "dev": true + }, + "@cspell/dict-dart": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-1.1.1.tgz", + "integrity": "sha512-XBOCpezXrgFN18kGEwqMpTUGZdw4BjCoJrNOo6qBdcdZySCrEHLwELraLOkcSba2kM4stmTp0t59FkwtP8TKOA==", + "dev": true + }, + "@cspell/dict-django": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-2.0.0.tgz", + "integrity": "sha512-GkJdJv6cmzrKcmq2/oxTXjKF5uv71r4eTqnFmgPbNBW1t+G4VYpzOf0QrVQrhx2RC4DdW5XfcTf+iS0FxHOTmw==", + "dev": true + }, + "@cspell/dict-dotnet": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-2.0.1.tgz", + "integrity": "sha512-b1n4crJRW0WZVf9Gp/52j/tDtjYiZ3N81fIyfqPlBrjsh/5AivfA697DYwQ2mr8ngNX7RsqRtYNQjealA1rEnQ==", + "dev": true + }, + "@cspell/dict-elixir": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-2.0.1.tgz", + "integrity": "sha512-eTTTxZt1FqGkM780yFDxsGHvTbWqvlK8YISSccK8FyrB6ULW+uflQlNS5AnWg3uWKC48b7pQott+odYCsPJ+Ow==", + "dev": true + }, + "@cspell/dict-en-gb": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz", + "integrity": "sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==", + "dev": true + }, + "@cspell/dict-en_us": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-2.3.3.tgz", + "integrity": "sha512-csyKeaNktfpvMkmE2GOPTwsrQm3wWhLKVaDRaGU0qTcIjDiCvqv/iYgrVrKRkoddA3kdNTZ8YNCcix7lb6VkOg==", + "dev": true + }, + "@cspell/dict-filetypes": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-2.1.1.tgz", + "integrity": "sha512-Oo0/mUbFHzsaATqRLdkV1RMoYns3aGzeKFIpVJg415GYtJ8EABXtEArYTXeMwlboyGTPvEk+PR2hBSTSfQTqmg==", + "dev": true + }, + "@cspell/dict-fonts": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-2.1.0.tgz", + "integrity": "sha512-hk7xsbfWEUhc136Xj7I2TD7ouKAfWwzCVAQaHBxcVXAsVxu7bDOGj4FvE2jBzlkSUY8A9Ww8qS0GOFvowJshVg==", + "dev": true + }, + "@cspell/dict-fullstack": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-2.0.6.tgz", + "integrity": "sha512-R2E2xvbHvvRwwurxfpBJDRIJjXBMfEPF5WNV3LTOEMRqkZtoYCeJK9aqc8LHlmJMtAbnN1cx//BCDIyTJ0rO0A==", + "dev": true + }, + "@cspell/dict-git": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-1.0.1.tgz", + "integrity": "sha512-Rk+eTof/9inF11lvxmkCRK+gODatA3qai8kSASv6OG/JfPvpj7fTHErx/rdgPw/LOTDUafnoTjTYmj7B2MOQXg==", + "dev": true + }, + "@cspell/dict-golang": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-3.0.1.tgz", + "integrity": "sha512-0KNfXTbxHW2l8iVjxeOf+KFv9Qrw3z5cyKnkuYJWlBTSB5KcUBfeKCb4fsds26VdANqiy6U91b4gDx5kNEmBjQ==", + "dev": true + }, + "@cspell/dict-haskell": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-2.0.1.tgz", + "integrity": "sha512-ooA23qIG7InOOxlLm67CNH5O2J85QsPHEAzEU9KEqVfYG5ovFs5tx6n9pHekDVk3MpQULpqfNUYDR0KigPLg5g==", + "dev": true + }, + "@cspell/dict-html": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-3.3.2.tgz", + "integrity": "sha512-cM5pQSEiqjrdk6cRFLrlLdWNT/J8399f/A6DjwjfYhHrGy0e/Rsjv76HZT0GlE1OqMoq9eG9jdQsfoYYgWTIpQ==", + "dev": true + }, + "@cspell/dict-html-symbol-entities": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-3.0.0.tgz", + "integrity": "sha512-04K7cPTcbYXmHICfiob4gZA1yaj4hpfM+Nl5WIJ1EAZsSGHdqmGEF28GuCjyQ8ZeKiJAsPt/vXuLBbjxkHqZyQ==", + "dev": true + }, + "@cspell/dict-java": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-2.0.0.tgz", + "integrity": "sha512-9f5LDATlAiXRGqxLxgqbOLlQxuMW2zcN7tBgxwtN+4u90vM03ZUOR/gKIuDV/y0ZuAiWBIjA73cjk8DJ13Q1eA==", + "dev": true + }, + "@cspell/dict-latex": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-2.0.9.tgz", + "integrity": "sha512-d1kTK6dJb5z6UcfASQWjqQlsjZvnoVOvMWxYtLpGksYf6gM4IgqoPVNMLYYK6xBS4T/uAnLIj975A6YuAeyZpg==", + "dev": true + }, + "@cspell/dict-lorem-ipsum": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-2.0.1.tgz", + "integrity": "sha512-s7Ft8UiloUJwgz4z8uLeFvCkeTcZ43HQl7mSAlZd76eW+keLSsdeGmLDx2zaciqo+MftPGyzygVCwaJjTGxiew==", + "dev": true + }, + "@cspell/dict-lua": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-2.0.0.tgz", + "integrity": "sha512-7WUEBEspSKtsq104WdIys1+DLqAxpJPzw74Py1TuE3fI5GvlzeSZkRFP2ya54GB2lCO4C3mq4M8EnitpibVDfw==", + "dev": true + }, + "@cspell/dict-node": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-2.0.1.tgz", + "integrity": "sha512-ztBWzhvI+YaMehICSJ65cohhjQqoztxf9vrS3YckOiVGBFvUMaFVNdX9klQkvrLcS/O4+2PzoGeIEkmf99amLA==", + "dev": true + }, + "@cspell/dict-npm": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-2.0.5.tgz", + "integrity": "sha512-KuPL5fKaqyG9ACrrinNt84FhVdh23VRtxDLO8MtGUdStca9tjfjPdmP2YF/5VkEKmpKYkfFKVcBUk9RgVkx5bw==", + "dev": true + }, + "@cspell/dict-php": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-2.0.0.tgz", + "integrity": "sha512-29WgU77eTO985LvMHwPi1pcpfopfCWfTdffDyqya0JIfOSaFUrlYKzGPkE4mRxcz2G3hXsaM0SRvBNdIRwEdUg==", + "dev": true + }, + "@cspell/dict-powershell": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-2.0.0.tgz", + "integrity": "sha512-6uvEhLiGmG3u9TFkM1TYcky6aL9Yk7Sk3KJwoTYBaQJY2KqrprgyQtW6yxIw9oU52VRHlq3KKvSAA9Q26+SIkQ==", + "dev": true + }, + "@cspell/dict-public-licenses": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-1.0.6.tgz", + "integrity": "sha512-Z9IUFPkkOpOsEdgPUfQOJNQ+qU6+iBAZWS/CR5sUqTX+s5VkPNVwQyVC2kdmgmE2U5qwzAPewG6nVKr2MVogwg==", + "dev": true + }, + "@cspell/dict-python": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-3.0.6.tgz", + "integrity": "sha512-tzxJ4sd9ZGhAUKg/WJJpQGDNtoHvM8Wn+iS2+PnQj2/LTHBW4mnaCogsGsBtYu8C4b2+BEQs+tc5808AeEfLug==", + "dev": true + }, + "@cspell/dict-r": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-1.0.3.tgz", + "integrity": "sha512-u2qeXd4cx/TvTVcmkvA+sK6f4K1uMAMO6QPMSr1pSvqGElPRP1mIBXmuiSuBzLO3LbsJuUEHw5Cp3/bxIB6rNA==", + "dev": true + }, + "@cspell/dict-ruby": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-2.0.2.tgz", + "integrity": "sha512-vVnUpSmGDbPjs7MHq741DsLHhQcoA4CnUCM9wsTorQ9AQRDAkDTbK/LcY8nM19MoXCb3eF8PFku5Jq+gqH0u7w==", + "dev": true + }, + "@cspell/dict-rust": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-2.0.1.tgz", + "integrity": "sha512-ATDpIh0VWpQdUIZa8zqqJY4wQz3q00BTXlQCodeOmObYSb23+L6KWWzJ8mKLgpbc1lqTkogWrqxiCxlrCmqNmg==", + "dev": true + }, + "@cspell/dict-scala": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-2.0.0.tgz", + "integrity": "sha512-MUwA2YKpqaQOSR4V1/CVGRNk8Ii5kf6I8Ch+4/BhRZRQXuwWbi21rDRYWPqdQWps7VNzAbbMA+PQDWsD5YY38g==", + "dev": true + }, + "@cspell/dict-software-terms": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-2.3.0.tgz", + "integrity": "sha512-rl+quUw68IxjWgeX/QDMgQsImZ1DaKzFyYMSGrCNcNPp4b4SMLwHCKoJ97/uOnUnw0jaBxueXoqp2iyN/QiOVw==", + "dev": true + }, + "@cspell/dict-swift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-1.0.3.tgz", + "integrity": "sha512-yOBLSaRD0AnkkkndJ8PuB82Evp6lA2xItf2AWsnPfCCgxp5Ojk6uUBC/WQBSkzkCAOGbXyHsu9D97tsOx2c6cw==", + "dev": true + }, + "@cspell/dict-typescript": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-2.0.2.tgz", + "integrity": "sha512-OIoSJsCw9WHX4eDikoF5/0QbptMPZjElOcMYdYCyV03nqV5n4ot72ysTexW95yW4+fQU6uDPNQvnrUnhXXEkTA==", + "dev": true + }, + "@cspell/dict-vue": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-2.0.2.tgz", + "integrity": "sha512-/MB0RS0Gn01s4pgmjy0FvsLfr3RRMrRphEuvTRserNcM8XVtoIVAtrjig/Gg0DPwDrN8Clm0L1j7iQay6S8D0g==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@hutson/parse-repository-url": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", + "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", + "dev": true + }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, + "@isaacs/string-locale-compare": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", + "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "requires": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "requires": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + } + }, + "@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "requires": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + } + }, + "@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "requires": { + "jest-get-type": "^29.6.3" + } + }, + "@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + } + }, + "@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "requires": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + } + }, + "@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.27.8" + } + }, + "@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } + } + }, + "@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "requires": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "requires": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } + } + }, + "@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "requires": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@kessler/tableify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@kessler/tableify/-/tableify-1.0.2.tgz", + "integrity": "sha512-e4psVV9Fe2eBfS9xK2rzQ9lE5xS4tARm7EJzDb6sVZy3F+EMyHJ67i0NdBVR9BRyQx7YhogMCbB6R1QwXuBxMg==", + "dev": true + }, + "@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "dev": true, + "requires": { + "debug": "^4.1.1" + } + }, + "@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "dev": true + }, + "@lerna-lite/cli": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@lerna-lite/cli/-/cli-2.5.1.tgz", + "integrity": "sha512-6Bs/w4rB/SVbiwbHfahm2W9wfUcvKcA34VBkVE8UrYOmwxOqODNdBUOUiZj76OTl5n5yByBf6MHWZN2MREPECw==", + "dev": true, + "requires": { + "@lerna-lite/core": "2.5.1", + "@lerna-lite/init": "2.5.1", + "dedent": "^1.5.1", + "dotenv": "^16.3.1", + "import-local": "^3.1.0", + "load-json-file": "^7.0.1", + "npmlog": "^7.0.1", + "yargs": "^17.7.2" + } + }, + "@lerna-lite/core": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@lerna-lite/core/-/core-2.5.1.tgz", + "integrity": "sha512-Bqx5e7/QiK1NzX8qfQyW3WP63Cw5mByCS0ZvrMUioQFJKw7BgXytOmg1OrcB2A7+hYwkZOiz25GWIUzHMvxVAA==", + "dev": true, + "requires": { + "@npmcli/run-script": "^7.0.1", + "chalk": "^5.3.0", + "clone-deep": "^4.0.1", + "config-chain": "^1.1.13", + "cosmiconfig": "^8.3.5", + "dedent": "^1.5.1", + "execa": "^8.0.1", + "fs-extra": "^11.1.1", + "glob-parent": "^6.0.2", + "globby": "^13.2.2", + "inquirer": "^9.2.10", + "is-ci": "^3.0.1", + "json5": "^2.2.3", + "load-json-file": "^7.0.1", + "minimatch": "^9.0.3", + "npm-package-arg": "^11.0.1", + "npmlog": "^7.0.1", + "p-map": "^6.0.0", + "p-queue": "^7.4.1", + "resolve-from": "^5.0.0", + "semver": "^7.5.4", + "slash": "^5.1.0", + "strong-log-transformer": "^2.1.0", + "write-file-atomic": "^5.0.1", + "write-json-file": "^5.0.0", + "write-pkg": "^6.0.0" + }, + "dependencies": { + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true + }, + "execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + } + }, + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true + }, + "globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "dependencies": { + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + } + } + }, + "human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true + }, + "inquirer": { + "version": "9.2.11", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.11.tgz", + "integrity": "sha512-B2LafrnnhbRzCWfAdOXisUzL89Kg8cVJlYmhqoi3flSiV/TveO+nsXwgKr9h9PIo+J1hz7nBSk6gegRIMBBf7g==", + "dev": true, + "requires": { + "@ljharb/through": "^2.3.9", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^5.0.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + } + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true + }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "requires": { + "path-key": "^4.0.0" + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "@lerna-lite/exec": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@lerna-lite/exec/-/exec-2.5.1.tgz", + "integrity": "sha512-fOIXy2E9m4m3N+ylvQmLW4sNMQYmiRy4PjOrDG4eIkiidIenqtDKi7LUGbECmatFgK5yqr2jo7WsQXcQP12xog==", + "dev": true, + "requires": { + "@lerna-lite/cli": "2.5.1", + "@lerna-lite/core": "2.5.1", + "@lerna-lite/filter-packages": "2.5.1", + "@lerna-lite/profiler": "2.5.1", + "chalk": "^5.3.0", + "dotenv": "^16.3.1", + "npmlog": "^7.0.1", + "p-map": "^6.0.0" + }, + "dependencies": { + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true + } + } + }, + "@lerna-lite/filter-packages": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@lerna-lite/filter-packages/-/filter-packages-2.5.1.tgz", + "integrity": "sha512-fFxRCm5Oo6KJJ/Er1OCUp0y2AmFK52egi37GyiQt4iLuqNfE/V+trOIof1OWMmR4sggk92QYcj98D1JXrBbomA==", + "dev": true, + "requires": { + "@lerna-lite/core": "2.5.1", + "multimatch": "^6.0.0", + "npmlog": "^7.0.1" + } + }, + "@lerna-lite/init": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@lerna-lite/init/-/init-2.5.1.tgz", + "integrity": "sha512-6deyLNCt2w3xS4oAho/B24LXeUBH6h3PE+D0BmX/vxvfq1UXDTXyBs+Ch2/H+oi6CMlWIQvYP/+oH7VZ9daVyQ==", + "dev": true, + "requires": { + "@lerna-lite/core": "2.5.1", + "fs-extra": "^11.1.1", + "p-map": "^6.0.0", + "write-json-file": "^5.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna-lite/list": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@lerna-lite/list/-/list-2.5.1.tgz", + "integrity": "sha512-bm9e7bwETDrLQLHXu78VlGhoUYZZbWBe53bmhTrR9CPsK5XJtgZHZKPuZYZCFyeIbQtyAYapXp5/aaI7RA3UxQ==", + "dev": true, + "requires": { + "@lerna-lite/cli": "2.5.1", + "@lerna-lite/core": "2.5.1", + "@lerna-lite/filter-packages": "2.5.1", + "@lerna-lite/listable": "2.5.1" + } + }, + "@lerna-lite/listable": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@lerna-lite/listable/-/listable-2.5.1.tgz", + "integrity": "sha512-Xm+YGY+jHk5SJ2FvQ/+Armfot6AM39rvkAN8ARENQeogrbycv+AiaFr1/QmAmmYRdj/2z5cNon3PPMkrElqsuw==", + "dev": true, + "requires": { + "@lerna-lite/core": "2.5.1", + "chalk": "^5.3.0", + "columnify": "^1.6.0" + }, + "dependencies": { + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true + } + } + }, + "@lerna-lite/profiler": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@lerna-lite/profiler/-/profiler-2.5.1.tgz", + "integrity": "sha512-fdQGZdLXJKZmpERn6ApKKdQfemK8eVOxzFJvM18QQ14cW2CGGHOSQ9e9uKMpW7M8DH4pGrbGI7m+XfcU1P/ONQ==", + "dev": true, + "requires": { + "@lerna-lite/core": "2.5.1", + "fs-extra": "^11.1.1", + "npmlog": "^7.0.1", + "upath": "^2.0.1" + }, + "dependencies": { + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna-lite/publish": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@lerna-lite/publish/-/publish-2.5.1.tgz", + "integrity": "sha512-bxvaaFUcQ1wiOLc1xWtekmsyobd7kqUoehzZ8HIStDIASMo+DZGVNyM+OZirI1F3Fz3PM/JbyRz+yo7Qp6kEVA==", + "dev": true, + "requires": { + "@lerna-lite/cli": "2.5.1", + "@lerna-lite/core": "2.5.1", + "@lerna-lite/version": "2.5.1", + "@npmcli/arborist": "^7.1.0", + "byte-size": "^8.1.1", + "chalk": "^5.3.0", + "columnify": "^1.6.0", + "fs-extra": "^11.1.1", + "glob": "^10.3.4", + "has-unicode": "^2.0.1", + "libnpmaccess": "^8.0.0", + "libnpmpublish": "^9.0.0", + "normalize-path": "^3.0.0", + "npm-package-arg": "^11.0.1", + "npm-packlist": "^8.0.0", + "npm-registry-fetch": "^16.0.0", + "npmlog": "^7.0.1", + "p-map": "^6.0.0", + "p-pipe": "^4.0.0", + "pacote": "^17.0.4", + "pify": "^6.1.0", + "read-package-json": "^7.0.0", + "semver": "^7.5.4", + "ssri": "^10.0.5", + "tar": "^6.2.0", + "temp-dir": "^3.0.0" + }, + "dependencies": { + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true + }, + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna-lite/run": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@lerna-lite/run/-/run-2.5.1.tgz", + "integrity": "sha512-GiYuXxrdjckPGOaLul+HWsFQkzTNVfZvwGiaYlEIBXEBErdjkTZ26SSs4SqGmLp4n2p9jF8rG+OdKc7/hdTz7Q==", + "dev": true, + "requires": { + "@lerna-lite/cli": "2.5.1", + "@lerna-lite/core": "2.5.1", + "@lerna-lite/filter-packages": "2.5.1", + "@lerna-lite/profiler": "2.5.1", + "chalk": "^5.3.0", + "fs-extra": "^11.1.1", + "npmlog": "^7.0.1", + "p-map": "^6.0.0" + }, + "dependencies": { + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true + }, + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + } + } + }, + "@lerna-lite/version": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@lerna-lite/version/-/version-2.5.1.tgz", + "integrity": "sha512-d7b2ZiCwTGbxE5LPkt43kRNSCBCgAEMYKVGMhpabm6YXOs9J5Si7gmcSQ9eTYctUjwY+QBUimRr/KFT4PvBfEw==", + "dev": true, + "requires": { + "@lerna-lite/cli": "2.5.1", + "@lerna-lite/core": "2.5.1", + "@octokit/plugin-enterprise-rest": "^6.0.1", + "@octokit/rest": "^19.0.13", + "chalk": "^5.3.0", + "conventional-changelog-angular": "^6.0.0", + "conventional-changelog-core": "^5.0.2", + "conventional-changelog-writer": "^6.0.1", + "conventional-commits-parser": "^5.0.0", + "conventional-recommended-bump": "^7.0.1", + "dedent": "^1.5.1", + "fs-extra": "^11.1.1", + "get-stream": "^8.0.1", + "git-url-parse": "^13.1.0", + "graceful-fs": "^4.2.11", + "is-stream": "^3.0.0", + "load-json-file": "^7.0.1", + "make-dir": "^4.0.0", + "minimatch": "^9.0.3", + "new-github-release-url": "^2.0.0", + "node-fetch": "^3.3.2", + "npm-package-arg": "^11.0.1", + "npmlog": "^7.0.1", + "p-map": "^6.0.0", + "p-pipe": "^4.0.0", + "p-reduce": "^3.0.0", + "pify": "^6.1.0", + "semver": "^7.5.4", + "slash": "^5.1.0", + "temp-dir": "^3.0.0", + "uuid": "^9.0.0", + "write-json-file": "^5.0.0" + }, + "dependencies": { + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true + }, + "conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "dev": true, + "requires": { + "JSONStream": "^1.3.5", + "is-text-path": "^2.0.0", + "meow": "^12.0.1", + "split2": "^4.0.0" + } + }, + "fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true + }, + "is-text-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "dev": true, + "requires": { + "text-extensions": "^2.0.0" + } + }, + "meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true + }, + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true + }, + "text-extensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", + "dev": true + } + } + }, + "@ljharb/resumer": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@ljharb/resumer/-/resumer-0.0.1.tgz", + "integrity": "sha512-skQiAOrCfO7vRTq53cxznMpks7wS1va95UCidALlOVWqvBAzwPVErwizDwoMqNVMEn1mDq0utxZd02eIrvF1lw==", + "dev": true, + "requires": { + "@ljharb/through": "^2.3.9" + } + }, + "@ljharb/through": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.11.tgz", + "integrity": "sha512-ccfcIDlogiXNq5KcbAwbaO7lMh3Tm1i3khMPYpxlK8hH/W53zN81KM9coerRLOnTGu3nfXIniAmQbRI9OxbC0w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "dev": true + }, + "@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dev": true, + "requires": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dev": true, + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + } + } + }, + "@nestjs/axios": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-0.1.0.tgz", + "integrity": "sha512-b2TT2X6BFbnNoeteiaxCIiHaFcSbVW+S5yygYqiIq5i6H77yIU3IVuLdpQkHq8/EqOWFwMopLN8jdkUT71Am9w==", + "dev": true, + "requires": { + "axios": "0.27.2" + } + }, + "@nestjs/common": { + "version": "9.3.11", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-9.3.11.tgz", + "integrity": "sha512-IFZ2G/5UKWC2Uo7tJ4SxGed2+aiA+sJyWeWsGTogKVDhq90oxVBToh+uCDeI31HNUpqYGoWmkletfty42zUd8A==", + "dev": true, + "requires": { + "iterare": "1.2.1", + "tslib": "2.5.0", + "uid": "2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "dev": true + } + } + }, + "@nestjs/core": { + "version": "9.3.11", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-9.3.11.tgz", + "integrity": "sha512-CI27a2JFd5rvvbgkalWqsiwQNhcP4EAG5BUK8usjp29wVp1kx30ghfBT8FLqIgmkRVo65A0IcEnWsxeXMntkxQ==", + "dev": true, + "requires": { + "@nuxtjs/opencollective": "0.3.2", + "fast-safe-stringify": "2.1.1", + "iterare": "1.2.1", + "path-to-regexp": "3.2.0", + "tslib": "2.5.0", + "uid": "2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "dev": true + } + } + }, + "@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "dev": true, + "requires": { + "@noble/hashes": "1.3.1" + } + }, + "@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/agent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.0.tgz", + "integrity": "sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q==", + "dev": true, + "requires": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true + } + } + }, + "@npmcli/arborist": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-7.2.0.tgz", + "integrity": "sha512-J6XCan+5nV6F94E0+9z//OnZADcqHw6HGDO0ynX+Ayd6GEopK0odq99V+UQjb8P1zexTmCWGvxp4jU5OM6NTtg==", + "dev": true, + "requires": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^3.1.0", + "@npmcli/installed-package-contents": "^2.0.2", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^7.0.0", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/query": "^3.0.1", + "@npmcli/run-script": "^7.0.1", + "bin-links": "^4.0.1", + "cacache": "^18.0.0", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^7.0.1", + "json-parse-even-better-errors": "^3.0.0", + "json-stringify-nice": "^1.1.4", + "minimatch": "^9.0.0", + "nopt": "^7.0.0", + "npm-install-checks": "^6.2.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.2", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.5", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" + }, + "dependencies": { + "hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "requires": { + "lru-cache": "^10.0.1" + } + }, + "json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true + }, + "lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true + } + } + }, + "@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "requires": { + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.3.tgz", + "integrity": "sha512-UZp9NwK+AynTrKvHn5k3KviW/hA5eENmFsu3iAPe7sWRt0lFUdsY/wXIYjpDFe7cdSNwOIzbObfwgt6eL5/2zw==", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "dependencies": { + "isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true + }, + "lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true + }, + "which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "requires": { + "isexe": "^3.1.1" + } + } + } + }, + "@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "requires": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "@npmcli/map-workspaces": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-3.0.4.tgz", + "integrity": "sha512-Z0TbvXkRbacjFFLpVpV0e2mheCh+WzQpcqL+4xp49uNJOxOnIAPZyXtUxZ5Qn3QBTGKA11Exjd9a5411rBrhDg==", + "dev": true, + "requires": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + } + }, + "@npmcli/metavuln-calculator": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-7.0.0.tgz", + "integrity": "sha512-Pw0tyX02VkpqlIQlG2TeiJNsdrecYeUU0ubZZa9pi3N37GCsxI+en43u4hYFdq+eSx1A9a9vwFAUyqEtKFsbHQ==", + "dev": true, + "requires": { + "cacache": "^18.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^17.0.0", + "semver": "^7.3.5" + }, + "dependencies": { + "json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true + } + } + }, + "@npmcli/name-from-folder": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-2.0.0.tgz", + "integrity": "sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==", + "dev": true + }, + "@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true + }, + "@npmcli/package-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.0.0.tgz", + "integrity": "sha512-OI2zdYBLhQ7kpNPaJxiflofYIpkNLi+lnGdzqUOfRmCF3r2l1nadcjtCYMJKv/Utm/ZtlffaUuTiAktPHbc17g==", + "dev": true, + "requires": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, + "dependencies": { + "hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "requires": { + "lru-cache": "^10.0.1" + } + }, + "json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true + }, + "lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true + }, + "normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "dev": true, + "requires": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + } + } + }, + "@npmcli/promise-spawn": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.0.tgz", + "integrity": "sha512-wBqcGsMELZna0jDblGd7UXgOby45TQaMWmbFwWX+SEotk4HV6zG2t6rT9siyLhPk4P6YYqgfL1UO8nMWDBVJXQ==", + "dev": true, + "requires": { + "which": "^4.0.0" + }, + "dependencies": { + "isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true + }, + "which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "requires": { + "isexe": "^3.1.1" + } + } + } + }, + "@npmcli/query": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-3.0.1.tgz", + "integrity": "sha512-0jE8iHBogf/+bFDj+ju6/UMLbJ39c8h6nSe6qile+dB7PJ0iV3gNqcb2vtt6WWCBrxv9uAjzUT/8vroluulidA==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "@npmcli/run-script": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.2.tgz", + "integrity": "sha512-Omu0rpA8WXvcGeY6DDzyRoY1i5DkCBkzyJ+m2u7PD6quzb0TvSqdIPOkTn8ZBOj7LbbcbMfZ3c5skwSu6m8y2w==", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^4.0.0" + }, + "dependencies": { + "isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true + }, + "which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "requires": { + "isexe": "^3.1.1" + } + } + } + }, + "@nuxtjs/opencollective": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", + "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "consola": "^2.15.0", + "node-fetch": "^2.6.1" + }, + "dependencies": { + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + } + } + }, + "@octokit/auth-token": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz", + "integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==", + "dev": true + }, + "@octokit/core": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz", + "integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==", + "dev": true, + "requires": { + "@octokit/auth-token": "^3.0.0", + "@octokit/graphql": "^5.0.0", + "@octokit/request": "^6.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz", + "integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==", + "dev": true, + "requires": { + "@octokit/types": "^9.0.0", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + }, + "dependencies": { + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true + } + } + }, + "@octokit/graphql": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz", + "integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==", + "dev": true, + "requires": { + "@octokit/request": "^6.0.0", + "@octokit/types": "^9.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/openapi-types": { + "version": "18.1.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.1.1.tgz", + "integrity": "sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw==", + "dev": true + }, + "@octokit/plugin-enterprise-rest": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz", + "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", + "dev": true + }, + "@octokit/plugin-paginate-rest": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz", + "integrity": "sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==", + "dev": true, + "requires": { + "@octokit/tsconfig": "^1.0.2", + "@octokit/types": "^9.2.3" + } + }, + "@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "dev": true + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz", + "integrity": "sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==", + "dev": true, + "requires": { + "@octokit/types": "^10.0.0" + }, + "dependencies": { + "@octokit/types": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz", + "integrity": "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==", + "dev": true, + "requires": { + "@octokit/openapi-types": "^18.0.0" + } + } + } + }, + "@octokit/request": { + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz", + "integrity": "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==", + "dev": true, + "requires": { + "@octokit/endpoint": "^7.0.0", + "@octokit/request-error": "^3.0.0", + "@octokit/types": "^9.0.0", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + }, + "dependencies": { + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true + }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + } + } + }, + "@octokit/request-error": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz", + "integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==", + "dev": true, + "requires": { + "@octokit/types": "^9.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "19.0.13", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.13.tgz", + "integrity": "sha512-/EzVox5V9gYGdbAI+ovYj3nXQT1TtTHRT+0eZPcuC05UFSWO3mdO9UY1C0i2eLF9Un1ONJkAk+IEtYGAC+TahA==", + "dev": true, + "requires": { + "@octokit/core": "^4.2.1", + "@octokit/plugin-paginate-rest": "^6.1.2", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^7.1.2" + } + }, + "@octokit/tsconfig": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz", + "integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==", + "dev": true + }, + "@octokit/types": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz", + "integrity": "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==", + "dev": true, + "requires": { + "@octokit/openapi-types": "^18.0.0" + } + }, + "@openapitools/openapi-generator-cli": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.7.0.tgz", + "integrity": "sha512-ieEpHTA/KsDz7ANw03lLPYyjdedDEXYEyYoGBRWdduqXWSX65CJtttjqa8ZaB1mNmIjMtchUHwAYQmTLVQ8HYg==", + "dev": true, + "requires": { + "@nestjs/axios": "0.1.0", + "@nestjs/common": "9.3.11", + "@nestjs/core": "9.3.11", + "@nuxtjs/opencollective": "0.3.2", + "chalk": "4.1.2", + "commander": "8.3.0", + "compare-versions": "4.1.4", + "concurrently": "6.5.1", + "console.table": "0.10.0", + "fs-extra": "10.1.0", + "glob": "7.1.6", + "inquirer": "8.2.5", + "lodash": "4.17.21", + "reflect-metadata": "0.1.13", + "rxjs": "7.8.0", + "tslib": "2.0.3" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "rxjs": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", + "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==", + "dev": true + } + } + }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, + "@polka/url": { + "version": "1.0.0-next.23", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz", + "integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==", + "dev": true + }, + "@scure/base": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.3.tgz", + "integrity": "sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==", + "dev": true + }, + "@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "dev": true, + "requires": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + } + }, + "@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "dev": true, + "requires": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + } + }, + "@sigstore/bundle": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.0.tgz", + "integrity": "sha512-89uOo6yh/oxaU8AeOUnVrTdVMcGk9Q1hJa7Hkvalc6G3Z3CupWk4Xe9djSgJm9fMkH69s0P0cVHUoKSOemLdng==", + "dev": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.1" + } + }, + "@sigstore/protobuf-specs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", + "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "dev": true + }, + "@sigstore/sign": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.0.tgz", + "integrity": "sha512-AAbmnEHDQv6CSfrWA5wXslGtzLPtAtHZleKOgxdQYvx/s76Fk6T6ZVt7w2IGV9j1UrFeBocTTQxaXG2oRrDhYA==", + "dev": true, + "requires": { + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "make-fetch-happen": "^13.0.0" + } + }, + "@sigstore/tuf": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.2.0.tgz", + "integrity": "sha512-KKATZ5orWfqd9ZG6MN8PtCIx4eevWSuGRKQvofnWXRpyMyUEpmrzg5M5BrCpjM+NfZ0RbNGOh5tCz/P2uoRqOA==", + "dev": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.1", + "tuf-js": "^2.1.0" + } + }, + "@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true + }, + "@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^3.0.0" + } + }, + "@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.1" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true + }, + "@tufjs/models": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.0.tgz", + "integrity": "sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg==", + "dev": true, + "requires": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + } + }, + "@types/adm-zip": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.0.tgz", + "integrity": "sha512-FCJBJq9ODsQZUNURo5ILAQueuA8WJhRvuihS3ke2iI25mJlfV2LK8jG2Qj2z2AWg8U0FtWWqBHVRetceLskSaw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/babel__core": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.3.tgz", + "integrity": "sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==", + "dev": true, + "requires": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.6", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.6.tgz", + "integrity": "sha512-66BXMKb/sUWbMdBNdMvajU7i/44RkrA3z/Yt1c7R5xejt8qh84iU54yUWCtm0QwGJlDcf/gg4zd/x4mpLAlb/w==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.3.tgz", + "integrity": "sha512-ciwyCLeuRfxboZ4isgdNZi/tkt06m8Tw6uGbBSBgWrnnZGNXiEyM27xc/PjXGQLqlZ6ylbgHMnm7ccF9tCkOeQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.20.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.3.tgz", + "integrity": "sha512-Lsh766rGEFbaxMIDH7Qa+Yha8cMVI3qAK6CHt3OR0YfxOIn5Z54iHiyDRycHrBqeIiqGa20Kpsv1cavfBKkRSw==", + "dev": true, + "requires": { + "@babel/types": "^7.20.7" + } + }, + "@types/eslint": { + "version": "8.44.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.6.tgz", + "integrity": "sha512-P6bY56TVmX8y9J87jHNgQh43h6VVU+6H7oN7hgvivV81K2XY8qJZ5vqPy/HdUoVIelii2kChYVzQanlswPWVFw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.6.tgz", + "integrity": "sha512-zfM4ipmxVKWdxtDaJ3MP3pBurDXOCoyjvlpE3u6Qzrmw4BPbfm4/ambIeTk/r/J0iq/+2/xp0Fmt+gFvXJY2PQ==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.3.tgz", + "integrity": "sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ==", + "dev": true + }, + "@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/graceful-fs": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.8.tgz", + "integrity": "sha512-NhRH7YzWq8WiNKVavKPBmtLYZHxNY19Hh+az28O/phfp68CF45pMFud+ZzJ8ewnxnC5smIdF3dqFeiSUQ5I+pw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", + "integrity": "sha512-V46MYLFp08Wf2mmaBhvgjStM3tPa+2GAdy/iqoX+noX1//zje2x4XmrIU0cAwyClATsTmahbtoQ2EwP7I5WSiA==", + "dev": true + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-zONci81DZYCZjiLe0r6equvZut0b+dBRPBN5kBDjsONnutYNtJMoWQ9uR2RkL1gLG9NMTzvf+29e5RFfPbeKhQ==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.2.tgz", + "integrity": "sha512-8toY6FgdltSdONav1XtUHl4LN1yTmLza+EuDazb/fEmRNCwjyqNVIQWs2IfC74IqjHkREs/nQ2FWq5kZU9IC0w==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.3.tgz", + "integrity": "sha512-1nESsePMBlf0RPRffLZi5ujYh7IH1BWL4y9pr+Bn3cJBdxz+RTP8bUFljLz9HvzhhOSWKdyBZ4DIivdL6rvgZg==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "29.5.3", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.3.tgz", + "integrity": "sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA==", + "dev": true, + "requires": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "@types/json-schema": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", + "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "@types/minimist": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.4.tgz", + "integrity": "sha512-Kfe/D3hxHTusnPNRbycJE1N77WHDsdS4AjUYIzlDzhDrS47NrwuL3YW4VITxwR7KCVpzwgy4Rbj829KSSQmwXQ==", + "dev": true + }, + "@types/node": { + "version": "16.18.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.41.tgz", + "integrity": "sha512-YZJjn+Aaw0xihnpdImxI22jqGbp0DCgTFKRycygjGx/Y27NnWFJa5FJ7P+MRT3u07dogEeMVh70pWpbIQollTA==", + "dev": true + }, + "@types/node-fetch": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz", + "integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + }, + "dependencies": { + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, + "@types/normalize-package-data": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz", + "integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.1.tgz", + "integrity": "sha512-3YmXzzPAdOTVljVMkTMBdBEvlOLg2cDQaDhnnhT3nT9uDbnJzjWhKlzb+desT12Y7tGqaN6d+AbozcKzyL36Ng==", + "dev": true + }, + "@types/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.2.tgz", + "integrity": "sha512-g7CK9nHdwjK2n0ymT2CW698FuWJRIx+RP6embAzZ2Qi8/ilIrA1Imt2LVSeHUzKvpoi7BhmmQcXz95eS0f2JXw==", + "dev": true + }, + "@types/tape": { + "version": "4.13.4", + "resolved": "https://registry.npmjs.org/@types/tape/-/tape-4.13.4.tgz", + "integrity": "sha512-0Mw8/FAMheD2MvyaFYDaAix7X5GfNjl/XI+zvqJdzC6N05BmHKz6Hwn+r7+8PEXDEKrC3V/irC9z7mrl5a130g==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/through": "*" + } + }, + "@types/tape-promise": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/tape-promise/-/tape-promise-4.0.1.tgz", + "integrity": "sha512-1yBeq9y0EmJ2RpxfXMPrFeD3yMetBapY9zArTexp/wCRdBToJac/y//rtcZZjmiArgodTqz0RrK0VxxySoKyVg==", + "dev": true, + "requires": { + "@types/tape": "*" + } + }, + "@types/through": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.32.tgz", + "integrity": "sha512-7XsfXIsjdfJM2wFDRAtEWp3zb2aVPk5QeyZxGlVK57q4u26DczMHhJmlhr0Jqv0THwxam/L8REXkj8M2I/lcvw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, + "@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.2.tgz", + "integrity": "sha512-5qcvofLPbfjmBfKaLfj/+f+Sbd6pN4zl7w7VSVI5uz7m9QZTuB2aZAa2uo1wHFBNN2x6g/SoTkXmd8mQnQF2Cw==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.4.0.tgz", + "integrity": "sha512-62o2Hmc7Gs3p8SLfbXcipjWAa6qk2wZGChXG2JbBtYpwSRmti/9KHLqfbLs9uDigOexG+3PaQ9G2g3201FWLKg==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.4.0", + "@typescript-eslint/type-utils": "6.4.0", + "@typescript-eslint/utils": "6.4.0", + "@typescript-eslint/visitor-keys": "6.4.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/parser": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.4.0.tgz", + "integrity": "sha512-I1Ah1irl033uxjxO9Xql7+biL3YD7w9IU8zF+xlzD/YxY6a4b7DYA08PXUUCbm2sEljwJF6ERFy2kTGAGcNilg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "6.4.0", + "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/typescript-estree": "6.4.0", + "@typescript-eslint/visitor-keys": "6.4.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.4.0.tgz", + "integrity": "sha512-TUS7vaKkPWDVvl7GDNHFQMsMruD+zhkd3SdVW0d7b+7Zo+bd/hXJQ8nsiUZMi1jloWo6c9qt3B7Sqo+flC1nig==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/visitor-keys": "6.4.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.4.0.tgz", + "integrity": "sha512-TvqrUFFyGY0cX3WgDHcdl2/mMCWCDv/0thTtx/ODMY1QhEiyFtv/OlLaNIiYLwRpAxAtOLOY9SUf1H3Q3dlwAg==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "6.4.0", + "@typescript-eslint/utils": "6.4.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/types": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.4.0.tgz", + "integrity": "sha512-+FV9kVFrS7w78YtzkIsNSoYsnOtrYVnKWSTVXoL1761CsCRv5wpDOINgsXpxD67YCLZtVQekDDyaxfjVWUJmmg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.0.tgz", + "integrity": "sha512-iDPJArf/K2sxvjOR6skeUCNgHR/tCQXBsa+ee1/clRKr3olZjZ/dSkXPZjG6YkPtnW6p5D1egeEPMCW6Gn4yLA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/visitor-keys": "6.4.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "dependencies": { + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "@typescript-eslint/utils": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.4.0.tgz", + "integrity": "sha512-BvvwryBQpECPGo8PwF/y/q+yacg8Hn/2XS+DqL/oRsOPK+RPt29h5Ui5dqOKHDlbXrAeHUTnyG3wZA0KTDxRZw==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.4.0", + "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/typescript-estree": "6.4.0", + "semver": "^7.5.4" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.0.tgz", + "integrity": "sha512-yJSfyT+uJm+JRDWYRYdCm2i+pmvXJSMtPR9Cq5/XQs4QIgNoLcoRtDdzsLbLsFM/c6um6ohQkg/MLxWvoIndJA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.4.0", + "eslint-visitor-keys": "^3.4.1" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true + }, + "@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "requires": { + "envinfo": "^7.7.3" + } + }, + "@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true + }, + "abitype": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-0.7.1.tgz", + "integrity": "sha512-VBkRHTDZf9Myaek/dO3yMmOzB/y2s3Zo6nVU7yaw1G+TvCHAjwaJzNGN9yo4K5D8bU/VZXKP1EJpRhFr862PlQ==", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, + "acorn-walk": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", + "dev": true + }, + "add-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", + "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==", + "dev": true + }, + "adm-zip": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", + "dev": true + }, + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "requires": { + "default-require-extensions": "^3.0.0" + } + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true + }, + "are-we-there-yet": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-4.0.1.tgz", + "integrity": "sha512-2zuA+jpOYBRgoBCfa+fB87Rk0oGJjDX6pxGzqH6f33NzUhG25Xur6R0u0Z9VVAq8Z5JvQpQI6j6rtonuivC8QA==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^4.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.4.2.tgz", + "integrity": "sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + } + } + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, + "array-differ": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-4.0.0.tgz", + "integrity": "sha512-Q6VPTLMsmXZ47ENG3V+wQyZS1ZxXMxFyYzA+Z/GMrJ6yIutAIEf9wTyroTzmGjNfox9/h3GdGBCVh43GVFx4Uw==", + "dev": true + }, + "array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true + }, + "array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + } + }, + "array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true + }, + "array-union": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", + "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", + "dev": true + }, + "array.prototype.every": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/array.prototype.every/-/array.prototype.every-1.1.5.tgz", + "integrity": "sha512-FfMQJ+/joFGXpRCltbzV3znaP5QxIhLFySo0fEPn3GuoYlud9LhknMCIxdYKC2qsM/6VHoSp6YGwe3EZXrEcwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "is-string": "^1.0.7" + } + }, + "array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + } + }, + "array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async-hook-domain": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-2.0.4.tgz", + "integrity": "sha512-14LjCmlK1PK8eDtTezR6WX8TMaYNIzBIsd2D1sGoGjgx0BuNMMoSdk7i/drlbtamy0AWv9yv2tkB+ASdmeqFIw==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dev": true, + "requires": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "requires": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "dependencies": { + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", + "dev": true + }, + "bin-links": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-4.0.3.tgz", + "integrity": "sha512-obsRaULtJurnfox/MDwgq6Yo9kzbv1CPTk/1/s7Z/61Lezc8IKkFCOXNeVLXz0456WRzBQmSsDWlai2tIhBsfA==", + "dev": true, + "requires": { + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bind-obj-methods": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bind-obj-methods/-/bind-obj-methods-3.0.0.tgz", + "integrity": "sha512-nLEaaz3/sEzNSyPWRsN9HNsqwk1AUyECtGj+XwGdIi3xABnEqecvXtIJ0wehQXuuER5uZ/5fTs2usONgYjG+iw==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + } + } + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", + "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.4", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", + "safe-buffer": "^5.2.1" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "dev": true + }, + "builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, + "byte-size": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-8.1.1.tgz", + "integrity": "sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg==", + "dev": true + }, + "cacache": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.0.tgz", + "integrity": "sha512-I7mVOPl3PUCeRub1U8YoGz2Lqv9WOBpobZ8RyWFXmReuILz+3OAyTa5oH3QPdtKZD7N0Yk00aLfzn0qvp8dZ1w==", + "dev": true, + "requires": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + } + } + }, + "cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true + }, + "cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + } + }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + } + } + }, + "call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + } + }, + "caniuse-lite": { + "version": "1.0.30001558", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001558.tgz", + "integrity": "sha512-/Et7DwLqpjS47JPEcz6VnxU9PwcIdVi0ciLXRWBQdj1XFye68pSQYpV0QtPTfUKWuOaEig+/Vez2l74eDc1tPQ==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.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" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "clear-module": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/clear-module/-/clear-module-4.1.2.tgz", + "integrity": "sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==", + "dev": true, + "requires": { + "parent-module": "^2.0.0", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "parent-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", + "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", + "dev": true, + "requires": { + "callsites": "^3.1.0" + } + } + } + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", + "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", + "dev": true + }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + } + } + }, + "cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "cmd-shim": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-6.0.2.tgz", + "integrity": "sha512-+FFYbB0YLaAkhkcrjkyNLYDiOsFSfRjwjY19LXk/psmMx1z00xlCv7hhQoTGXXIKi+YXHL/iiFo8NqMVQX9nOw==", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true + }, + "columnify": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", + "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", + "dev": true, + "requires": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, + "comment-json": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.3.tgz", + "integrity": "sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==", + "dev": true, + "requires": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + } + }, + "common-ancestor-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "compare-versions": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.4.tgz", + "integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "concurrently": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.5.1.tgz", + "integrity": "sha512-FlSwNpGjWQfRwPLXvJ/OgysbBxPkWpiVjy1042b0U7on7S7qwwMIILRj7WTN1mTgqa582bG6NFuScOoh6Zgdag==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" + }, + "dependencies": { + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + } + } + }, + "consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==", + "dev": true + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "console.table": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz", + "integrity": "sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==", + "dev": true, + "requires": { + "easy-table": "1.1.0" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "dev": true + }, + "conventional-changelog-angular": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz", + "integrity": "sha512-6qLgrBF4gueoC7AFVHu51nHL9pF9FRjXrH+ceVf7WmAfH3gs+gEYOkvxhjMPjZu57I4AGUGoNTY8V7Hrgf1uqg==", + "dev": true, + "requires": { + "compare-func": "^2.0.0" + } + }, + "conventional-changelog-conventionalcommits": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-6.1.0.tgz", + "integrity": "sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==", + "dev": true, + "requires": { + "compare-func": "^2.0.0" + } + }, + "conventional-changelog-core": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-5.0.2.tgz", + "integrity": "sha512-RhQOcDweXNWvlRwUDCpaqXzbZemKPKncCWZG50Alth72WITVd6nhVk9MJ6w1k9PFNBcZ3YwkdkChE+8+ZwtUug==", + "dev": true, + "requires": { + "add-stream": "^1.0.0", + "conventional-changelog-writer": "^6.0.0", + "conventional-commits-parser": "^4.0.0", + "dateformat": "^3.0.3", + "get-pkg-repo": "^4.2.1", + "git-raw-commits": "^3.0.0", + "git-remote-origin-url": "^2.0.0", + "git-semver-tags": "^5.0.0", + "normalize-package-data": "^3.0.3", + "read-pkg": "^3.0.0", + "read-pkg-up": "^3.0.0" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "git-raw-commits": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-3.0.0.tgz", + "integrity": "sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==", + "dev": true, + "requires": { + "dargs": "^7.0.0", + "meow": "^8.1.2", + "split2": "^3.2.2" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "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 + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "dependencies": { + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + } + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "conventional-changelog-preset-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-3.0.0.tgz", + "integrity": "sha512-qy9XbdSLmVnwnvzEisjxdDiLA4OmV3o8db+Zdg4WiFw14fP3B6XNz98X0swPPpkTd/pc1K7+adKgEDM1JCUMiA==", + "dev": true + }, + "conventional-changelog-writer": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-6.0.1.tgz", + "integrity": "sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==", + "dev": true, + "requires": { + "conventional-commits-filter": "^3.0.0", + "dateformat": "^3.0.3", + "handlebars": "^4.7.7", + "json-stringify-safe": "^5.0.1", + "meow": "^8.1.2", + "semver": "^7.0.0", + "split": "^1.0.1" + } + }, + "conventional-commits-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-3.0.0.tgz", + "integrity": "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==", + "dev": true, + "requires": { + "lodash.ismatch": "^4.4.0", + "modify-values": "^1.0.1" + } + }, + "conventional-commits-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-4.0.0.tgz", + "integrity": "sha512-WRv5j1FsVM5FISJkoYMR6tPk07fkKT0UodruX4je86V4owk451yjXAKzKAPOs9l7y59E2viHUS9eQ+dfUA9NSg==", + "dev": true, + "requires": { + "JSONStream": "^1.3.5", + "is-text-path": "^1.0.1", + "meow": "^8.1.2", + "split2": "^3.2.2" + } + }, + "conventional-recommended-bump": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-7.0.1.tgz", + "integrity": "sha512-Ft79FF4SlOFvX4PkwFDRnaNiIVX7YbmqGU0RwccUaiGvgp3S0a8ipR2/Qxk31vclDNM+GSdJOVs2KrsUCjblVA==", + "dev": true, + "requires": { + "concat-stream": "^2.0.0", + "conventional-changelog-preset-loader": "^3.0.0", + "conventional-commits-filter": "^3.0.0", + "conventional-commits-parser": "^4.0.0", + "git-raw-commits": "^3.0.0", + "git-semver-tags": "^5.0.0", + "meow": "^8.1.2" + }, + "dependencies": { + "git-raw-commits": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-3.0.0.tgz", + "integrity": "sha512-b5OHmZ3vAgGrDn/X0kS+9qCfNKWe4K/jFnhwzVWWg0/k5eLa3060tZShrRg8Dja5kPc+YjS0Gc6y7cRr44Lpjw==", + "dev": true, + "requires": { + "dargs": "^7.0.0", + "meow": "^8.1.2", + "split2": "^3.2.2" + } + } + } + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "requires": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + } + }, + "cosmiconfig-typescript-loader": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.4.0.tgz", + "integrity": "sha512-BabizFdC3wBHhbI4kJh0VkQP9GkBfoHPydD0COMce1nJ1kJAB3F2TmJ/I7diULBKtmEWSwEbuN/KDtgnmUUVmw==", + "dev": true + }, + "cp-file": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-9.1.0.tgz", + "integrity": "sha512-3scnzFj/94eb7y4wyXRWwvzLFaQp87yyfTnChIjlfYrVqp5lVO3E2hIJMeQIltUT0K2ZAB3An1qXcBmwGyvuwA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "nested-error-stacks": "^2.0.0", + "p-event": "^4.1.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "cpy": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cpy/-/cpy-9.0.1.tgz", + "integrity": "sha512-D9U0DR5FjTCN3oMTcFGktanHnAG5l020yvOCR1zKILmAyPP7I/9pl6NFgRbDcmSENtbK1sQLBz1p9HIOlroiNg==", + "dev": true, + "requires": { + "arrify": "^3.0.0", + "cp-file": "^9.1.0", + "globby": "^13.1.1", + "junk": "^4.0.0", + "micromatch": "^4.0.4", + "nested-error-stacks": "^2.1.0", + "p-filter": "^3.0.0", + "p-map": "^5.3.0" + }, + "dependencies": { + "aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "requires": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + } + }, + "arrify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz", + "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==", + "dev": true + }, + "clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "dev": true, + "requires": { + "escape-string-regexp": "5.0.0" + } + }, + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true + }, + "globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true + }, + "p-map": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", + "dev": true, + "requires": { + "aggregate-error": "^4.0.0" + } + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + } + } + }, + "cpy-cli": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/cpy-cli/-/cpy-cli-4.2.0.tgz", + "integrity": "sha512-b04b+cbdr29CdpREPKw/itrfjO43Ty0Aj7wRM6M6LoE4GJxZJCk9Xp+Eu1IqztkKh3LxIBt1tDplENsa6KYprg==", + "dev": true, + "requires": { + "cpy": "^9.0.0", + "meow": "^10.1.2" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "camelcase-keys": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", + "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", + "dev": true, + "requires": { + "camelcase": "^6.3.0", + "map-obj": "^4.1.0", + "quick-lru": "^5.1.1", + "type-fest": "^1.2.1" + } + }, + "decamelize": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", + "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", + "dev": true + }, + "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, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true + }, + "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, + "requires": { + "p-locate": "^5.0.0" + } + }, + "meow": { + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/meow/-/meow-10.1.5.tgz", + "integrity": "sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.2", + "camelcase-keys": "^7.0.0", + "decamelize": "^5.0.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.2", + "read-pkg-up": "^8.0.0", + "redent": "^4.0.0", + "trim-newlines": "^4.0.2", + "type-fest": "^1.2.2", + "yargs-parser": "^20.2.9" + } + }, + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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, + "requires": { + "p-limit": "^3.0.2" + } + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + }, + "read-pkg": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", + "integrity": "sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^3.0.2", + "parse-json": "^5.2.0", + "type-fest": "^1.0.1" + } + }, + "read-pkg-up": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-8.0.0.tgz", + "integrity": "sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==", + "dev": true, + "requires": { + "find-up": "^5.0.0", + "read-pkg": "^6.0.0", + "type-fest": "^1.0.1" + } + }, + "redent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", + "integrity": "sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==", + "dev": true, + "requires": { + "indent-string": "^5.0.0", + "strip-indent": "^4.0.0" + } + }, + "strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "dev": true, + "requires": { + "min-indent": "^1.0.1" + } + }, + "trim-newlines": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.1.1.tgz", + "integrity": "sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==", + "dev": true + }, + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true + } + } + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } + }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "requires": { + "node-fetch": "^2.6.12" + }, + "dependencies": { + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + } + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "cspell": { + "version": "5.21.2", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.21.2.tgz", + "integrity": "sha512-yG14BUumeIcsuSEcM//+9XpbUR6a6FlAxfaVI4e5t6ZZE5tPgDE0PNIVr/jAiLPVm9qUfnq+oNdZE8wmVUbMzw==", + "dev": true, + "requires": { + "@cspell/cspell-pipe": "^5.21.2", + "chalk": "^4.1.2", + "commander": "^9.2.0", + "cspell-gitignore": "^5.21.2", + "cspell-glob": "^5.21.2", + "cspell-lib": "^5.21.2", + "fast-json-stable-stringify": "^2.1.0", + "file-entry-cache": "^6.0.1", + "fs-extra": "^10.1.0", + "get-stdin": "^8.0.0", + "glob": "^8.0.3", + "imurmurhash": "^0.1.4", + "semver": "^7.3.7", + "strip-ansi": "^6.0.1", + "vscode-uri": "^3.0.3" + }, + "dependencies": { + "commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "cspell-gitignore": { + "version": "5.21.2", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.21.2.tgz", + "integrity": "sha512-MdNmRRbglmCi20LU7ORZM1gyPSe1gL+4A8Pn+Jm+W5ropSbotzCqiO8BcyhRMNb3lAdMGGrj7gmYtiQ5C/fXIQ==", + "dev": true, + "requires": { + "cspell-glob": "^5.21.2", + "find-up": "^5.0.0" + }, + "dependencies": { + "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, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "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, + "requires": { + "p-locate": "^5.0.0" + } + }, + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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, + "requires": { + "p-limit": "^3.0.2" + } + } + } + }, + "cspell-glob": { + "version": "5.21.2", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-5.21.2.tgz", + "integrity": "sha512-AabqzG31UWy4CSz1xJIK4qzXcarxuRFP9OD2EX8iDtEo0tQJLGoTHE+UpNDBPWTHearE0BZPhpMDF/radtZAgw==", + "dev": true, + "requires": { + "micromatch": "^4.0.5" + } + }, + "cspell-io": { + "version": "5.21.2", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-5.21.2.tgz", + "integrity": "sha512-3J4cLuN59R7ARiRZ8ke5QwlC5uPfzHLVELOtEAmsTIjuUMvr7BpbrdCuTsUvLkAqYE9NA5eqolqQm3GLXnECNw==", + "dev": true + }, + "cspell-lib": { + "version": "5.21.2", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.21.2.tgz", + "integrity": "sha512-emAFXtDfs84FoMlhOxZYxYVvbCoCN0LxN0obIRvCsvFCLUPj9y7vHv/Tu/01ZyAPeo2r6gkqhanJpQyoIDA1yg==", + "dev": true, + "requires": { + "@cspell/cspell-bundled-dicts": "^5.21.2", + "@cspell/cspell-pipe": "^5.21.2", + "@cspell/cspell-types": "^5.21.2", + "clear-module": "^4.1.2", + "comment-json": "^4.2.2", + "configstore": "^5.0.1", + "cosmiconfig": "^7.0.1", + "cspell-glob": "^5.21.2", + "cspell-io": "^5.21.2", + "cspell-trie-lib": "^5.21.2", + "fast-equals": "^3.0.2", + "find-up": "^5.0.0", + "fs-extra": "^10.1.0", + "gensequence": "^3.1.1", + "import-fresh": "^3.3.0", + "resolve-from": "^5.0.0", + "resolve-global": "^1.0.0", + "vscode-languageserver-textdocument": "^1.0.4", + "vscode-uri": "^3.0.3" + }, + "dependencies": { + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "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, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "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, + "requires": { + "p-locate": "^5.0.0" + } + }, + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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, + "requires": { + "p-limit": "^3.0.2" + } + } + } + }, + "cspell-trie-lib": { + "version": "5.21.2", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.21.2.tgz", + "integrity": "sha512-iux2F+85jDlBEJZgikfPT5SUZMwuFjNqEJiO1SO+xfQG+2MFV9CaHTsoRJIGNy3udMm1mw0GMY5UIVAodwlnhg==", + "dev": true, + "requires": { + "@cspell/cspell-pipe": "^5.21.2", + "fs-extra": "^10.1.0", + "gensequence": "^3.1.1" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", + "dev": true + }, + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true + }, + "date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.21.0" + } + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true + } + } + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + } + } + }, + "dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true + }, + "deep-equal": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", + "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.1", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, + "deepmerge-ts": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-5.1.0.tgz", + "integrity": "sha512-eS8dRJOckyo9maw9Tu5O5RUi/4inFLrnoLkBe3cPfDMx3WZioXtmOew4TXQaxq7Rhl4xjDtR7c6x8nNTxOvbFw==", + "dev": true + }, + "default-require-extensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", + "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", + "dev": true, + "requires": { + "strip-bom": "^4.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } + } + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true + }, + "define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "dev": true + }, + "del": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/del/-/del-7.1.0.tgz", + "integrity": "sha512-v2KyNk7efxhlyHpjEvfyxaAihKKK0nWCuf6ZtqZcFFpQRG0bJ12Qsr0RpvsICMjAAZ8DOVCxrlqpxISlMHC4Kg==", + "dev": true, + "requires": { + "globby": "^13.1.2", + "graceful-fs": "^4.2.10", + "is-glob": "^4.0.3", + "is-path-cwd": "^3.0.0", + "is-path-inside": "^4.0.0", + "p-map": "^5.5.0", + "rimraf": "^3.0.2", + "slash": "^4.0.0" + }, + "dependencies": { + "aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "requires": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + } + }, + "clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "dev": true, + "requires": { + "escape-string-regexp": "5.0.0" + } + }, + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true + }, + "globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true + }, + "p-map": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", + "dev": true, + "requires": { + "aggregate-error": "^4.0.0" + } + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + } + } + }, + "del-cli": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/del-cli/-/del-cli-4.0.1.tgz", + "integrity": "sha512-KtR/6cBfZkGDAP2NA7z+bP4p1OMob3wjN9mq13+SWvExx6jT9gFWfLgXEeX8J2B47OKeNCq9yTONmtryQ+m+6g==", + "dev": true, + "requires": { + "del": "^6.0.0", + "meow": "^10.1.0" + }, + "dependencies": { + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "camelcase-keys": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", + "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", + "dev": true, + "requires": { + "camelcase": "^6.3.0", + "map-obj": "^4.1.0", + "quick-lru": "^5.1.1", + "type-fest": "^1.2.1" + } + }, + "decamelize": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", + "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", + "dev": true + }, + "del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dev": true, + "requires": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + } + }, + "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, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "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, + "requires": { + "p-locate": "^5.0.0" + } + }, + "meow": { + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/meow/-/meow-10.1.5.tgz", + "integrity": "sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.2", + "camelcase-keys": "^7.0.0", + "decamelize": "^5.0.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.2", + "read-pkg-up": "^8.0.0", + "redent": "^4.0.0", + "trim-newlines": "^4.0.2", + "type-fest": "^1.2.2", + "yargs-parser": "^20.2.9" + } + }, + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + }, + "read-pkg": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", + "integrity": "sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^3.0.2", + "parse-json": "^5.2.0", + "type-fest": "^1.0.1" + } + }, + "read-pkg-up": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-8.0.0.tgz", + "integrity": "sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==", + "dev": true, + "requires": { + "find-up": "^5.0.0", + "read-pkg": "^6.0.0", + "type-fest": "^1.0.1" + } + }, + "redent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", + "integrity": "sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==", + "dev": true, + "requires": { + "indent-string": "^5.0.0", + "strip-indent": "^4.0.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "dev": true, + "requires": { + "min-indent": "^1.0.1" + } + }, + "trim-newlines": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.1.1.tgz", + "integrity": "sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==", + "dev": true + }, + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "dev": true + }, + "des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "detect-indent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.1.tgz", + "integrity": "sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==", + "dev": true + }, + "detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "dev": true + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "domain-browser": { + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", + "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==", + "dev": true + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true + }, + "dotignore": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", + "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "easy-table": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz", + "integrity": "sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==", + "dev": true, + "requires": { + "wcwidth": ">=1.0.1" + } + }, + "electron-to-chromium": { + "version": "1.4.569", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.569.tgz", + "integrity": "sha512-LsrJjZ0IbVy12ApW3gpYpcmHS3iRxH4bkKOW98y1/D+3cvDUWGcbzbsFinfUS8knpcZk/PG/2p/RnkMCYN7PVg==", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + } + }, + "enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + } + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "envinfo": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz", + "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==", + "dev": true + }, + "eol": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/eol/-/eol-0.9.1.tgz", + "integrity": "sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==", + "dev": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + } + }, + "es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "es-main": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-main/-/es-main-1.2.0.tgz", + "integrity": "sha512-A4tCSY43O/mH4rHjG1n0mI4DhK2BmKDr8Lk8PXK/GBB6zxGFGmIW4bbkbTQ2Gi9iNamMZ9vbGrwjZOIeiM7vMw==", + "dev": true + }, + "es-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", + "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==", + "dev": true + }, + "es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "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 + }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true + }, + "eslint-config-standard": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz", + "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.28.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", + "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.findlastindex": "^1.2.2", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.8.0", + "has": "^1.0.3", + "is-core-module": "^2.13.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.6", + "object.groupby": "^1.0.0", + "object.values": "^1.1.6", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "eslint-plugin-prettier": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", + "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-promise": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz", + "integrity": "sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw==", + "dev": true + }, + "eslint-plugin-standard": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-5.0.0.tgz", + "integrity": "sha512-eSIXPc9wBM4BrniMzJRBm2uoVuXz2EPa+NXPk2+itrVt+r5SbKFERx/IgrK/HmfjddyKVz2f+j+7gBRvu19xLg==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "requires": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, + "eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "events-to-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", + "integrity": "sha512-inRWzRY7nG+aXZxBzEqYKB3HPgwflZRopAjDCHv0whhRx+MTUr1ei0ICZUypdyE0HRm4L2d5VEcIqLD6yl+BFA==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true + }, + "expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "requires": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + } + }, + "exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "fast-equals": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-3.0.3.tgz", + "integrity": "sha512-NCe8qxnZFARSHGztGMZOO/PC1qa5MIFB5Hp66WdzbCRAz8U8US3bx1UTgLS49efBQPcUtO9gf5oVEY8o7y/7Kg==", + "dev": true + }, + "fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, + "fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, + "figures": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", + "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", + "dev": true, + "requires": { + "escape-string-regexp": "^5.0.0", + "is-unicode-supported": "^1.2.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true + } + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "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==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "filter-obj": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-2.0.2.tgz", + "integrity": "sha512-lO3ttPjHZRfjMcxWKb1j1eDhTFsu4meeR3lnMcnBFhk6RuLhvEiuALu2TlfL310ph4lCYYwgF/ElIjdP739tdg==", + "dev": true + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "findit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", + "integrity": "sha512-ENZS237/Hr8bjczn5eKuBohLgaD0JyUd0arxretR1f9RO46vZHA1b2y0VorgGV3WaOT3c+78P8h7v4JGJ1i/rg==", + "dev": true + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + } + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true + }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "requires": { + "fetch-blob": "^3.1.2" + } + }, + "fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true + }, + "fs-exists-cached": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz", + "integrity": "sha512-kSxoARUDn4F2RPXX48UXnaFKwVU7Ivd/6qpzZL29MCDmr9sTvybv4gFCp+qaI4fM9m0z9fgz/yJvi56GAz+BZg==", + "dev": true + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "requires": { + "minipass": "^7.0.3" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "function-loop": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-2.0.1.tgz", + "integrity": "sha512-ktIR+O6i/4h+j/ZhZJNdzeI4i9lEPeEK6UPR2EVyTVBqOwcU3Za9xYKLH64ZR9HmcROyRrOkizNyjjtWJzDDkQ==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "gauge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-5.0.1.tgz", + "integrity": "sha512-CmykPMJGuNan/3S4kZOpvvPYSNqSHANiWnh9XcMU2pSjtBfF0XzZ2p1bFAxTbnFxyBuPxQYHhzwaoOmUdqzvxQ==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^4.0.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + } + } + }, + "gensequence": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-3.1.1.tgz", + "integrity": "sha512-ys3h0hiteRwmY6BsvSttPmkhC0vEQHPJduANBRtH/dlDPZ0UBIb/dXy80IcckXyuQ6LKg+PloRqvGER9IS7F7g==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-pkg-repo": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", + "integrity": "sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA==", + "dev": true, + "requires": { + "@hutson/parse-repository-url": "^3.0.0", + "hosted-git-info": "^4.0.0", + "through2": "^2.0.0", + "yargs": "^16.2.0" + }, + "dependencies": { + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "git-hooks-list": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-1.0.3.tgz", + "integrity": "sha512-Y7wLWcrLUXwk2noSka166byGCvhMtDRpgHdzCno1UQv/n/Hegp++a2xBWJL1lJarnKD3SWaljD+0z1ztqxuKyQ==", + "dev": true + }, + "git-raw-commits": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", + "integrity": "sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==", + "dev": true, + "requires": { + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + } + }, + "git-remote-origin-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", + "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", + "dev": true, + "requires": { + "gitconfiglocal": "^1.0.0", + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + } + } + }, + "git-semver-tags": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-5.0.1.tgz", + "integrity": "sha512-hIvOeZwRbQ+7YEUmCkHqo8FOLQZCEn18yevLHADlFPZY02KJGsu5FZt9YW/lybfK2uhWFI7Qg/07LekJiTv7iA==", + "dev": true, + "requires": { + "meow": "^8.1.2", + "semver": "^7.0.0" + } + }, + "git-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-7.0.0.tgz", + "integrity": "sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==", + "dev": true, + "requires": { + "is-ssh": "^1.4.0", + "parse-url": "^8.1.0" + } + }, + "git-url-parse": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.1.tgz", + "integrity": "sha512-PCFJyeSSdtnbfhSNRw9Wk96dDCNx+sogTe4YNXeXSJxt7xz5hvXekuRn9JX7m+Mf4OscCu8h+mtAl3+h5Fo8lQ==", + "dev": true, + "requires": { + "git-up": "^7.0.0" + } + }, + "gitconfiglocal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", + "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==", + "dev": true, + "requires": { + "ini": "^1.3.2" + } + }, + "glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + }, + "dependencies": { + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-12.2.0.tgz", + "integrity": "sha512-wiSuFQLZ+urS9x2gGPl1H5drc5twabmm4m2gTR27XDFyjUHJUNsS8o/2aKyIF6IoBaR630atdher0XJ5g6OMmA==", + "dev": true, + "requires": { + "array-union": "^3.0.1", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.7", + "ignore": "^5.1.9", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "dependencies": { + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + } + } + }, + "google-protobuf": { + "version": "3.21.2", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", + "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==", + "dev": true + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "requires": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "grpc-tools": { + "version": "1.12.4", + "resolved": "https://registry.npmjs.org/grpc-tools/-/grpc-tools-1.12.4.tgz", + "integrity": "sha512-5+mLAJJma3BjnW/KQp6JBjUMgvu7Mu3dBvBPd1dcbNIb+qiR0817zDpgPjS7gRb+l/8EVNIa3cB02xI9JLToKg==", + "dev": true, + "requires": { + "@mapbox/node-pre-gyp": "^1.0.5" + } + }, + "grpc_tools_node_protoc_ts": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/grpc_tools_node_protoc_ts/-/grpc_tools_node_protoc_ts-5.3.3.tgz", + "integrity": "sha512-M/YrklvVXMtuuj9kb42PxeouZhs7Ul+R4e/31XwrankUcKL8cQQP50Q9q+KEHGyHQaPt6VtKKsxMgLaKbCxeww==", + "dev": true, + "requires": { + "google-protobuf": "3.15.8", + "handlebars": "4.7.7" + }, + "dependencies": { + "google-protobuf": { + "version": "3.15.8", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.15.8.tgz", + "integrity": "sha512-2jtfdqTaSxk0cuBJBtTTWsot4WtR9RVr2rXg7x7OoqiuOKopPrwXpM1G4dXIkLcUNRh3RKzz76C8IOkksZSeOw==", + "dev": true + }, + "handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + } + } + }, + "gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "requires": { + "duplexer": "^0.1.2" + } + }, + "handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, + "has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "dev": true + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-dynamic-import": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-dynamic-import/-/has-dynamic-import-2.0.1.tgz", + "integrity": "sha512-X3fbtsZmwb6W7fJGR9o7x65fZoodygCrZ3TVycvghP62yYQfS0t4RS0Qcz+j5tQYUKeSWS09tHkWW6WhFV3XhQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.2" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dev": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "dependencies": { + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + } + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", + "dev": true + }, + "https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "ignore-walk": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", + "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", + "dev": true, + "requires": { + "minimatch": "^9.0.0" + } + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "inquirer": { + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "dependencies": { + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true + }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "requires": { + "ci-info": "^3.2.0" + } + }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true + }, + "is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-3.0.0.tgz", + "integrity": "sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==", + "dev": true + }, + "is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true + }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-ssh": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.0.tgz", + "integrity": "sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==", + "dev": true, + "requires": { + "protocols": "^2.0.1" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-text-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", + "dev": true, + "requires": { + "text-extensions": "^1.0.0" + } + }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.11" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true + }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "requires": { + "append-transform": "^2.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", + "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + } + }, + "istanbul-lib-processinfo": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", + "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.3", + "istanbul-lib-coverage": "^3.2.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^8.3.2" + }, + "dependencies": { + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "iterare": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", + "dev": true + }, + "jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, + "jest": { + "version": "29.6.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.2.tgz", + "integrity": "sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg==", + "dev": true, + "requires": { + "@jest/core": "^29.6.2", + "@jest/types": "^29.6.1", + "import-local": "^3.0.2", + "jest-cli": "^29.6.2" + }, + "dependencies": { + "jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "requires": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + } + } + } + }, + "jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "requires": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "dependencies": { + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + } + } + }, + "jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "requires": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + } + }, + "jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + } + }, + "jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "requires": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + } + }, + "jest-extended": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jest-extended/-/jest-extended-4.0.1.tgz", + "integrity": "sha512-KM6dwuBUAgy6QONuR19CGubZB9Hkjqvl/d5Yc/FXsdB8+gsGxB2VQ+NEdOrr95J4GMPeLnDoPOKyi6+mKCCnZQ==", + "dev": true, + "requires": { + "jest-diff": "^29.0.0", + "jest-get-type": "^29.0.0" + } + }, + "jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true + }, + "jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "requires": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + } + }, + "jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + } + }, + "jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true + }, + "jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true + }, + "jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "dependencies": { + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "requires": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + } + }, + "jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "requires": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "dependencies": { + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + } + } + }, + "jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "requires": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } + } + }, + "jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + } + }, + "jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "requires": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "requires": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json-stringify-nice": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", + "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true + }, + "junk": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/junk/-/junk-4.0.1.tgz", + "integrity": "sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==", + "dev": true + }, + "just-diff": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz", + "integrity": "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==", + "dev": true + }, + "just-diff-apply": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.5.0.tgz", + "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==", + "dev": true + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "libnpmaccess": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-8.0.1.tgz", + "integrity": "sha512-MWbnWIfxLKol+BgC1NR1as1JwM5ufZASd6CaENJjNe4JpJ0gx71xhpYY5SvNMZnVBahocYZWP6+SPQdyD0abEQ==", + "dev": true, + "requires": { + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0" + } + }, + "libnpmpublish": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-9.0.1.tgz", + "integrity": "sha512-w5Ev46SnPaEpjfa0a5+p2vYSB19nONF/mRX8RcIRp2gpPxMWldFVZy/fXei/uflMLQq33mjKMqiVoNcz6ZJCYg==", + "dev": true, + "requires": { + "ci-info": "^3.6.1", + "normalize-package-data": "^6.0.0", + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7", + "sigstore": "^2.1.0", + "ssri": "^10.0.5" + }, + "dependencies": { + "hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "requires": { + "lru-cache": "^10.0.1" + } + }, + "lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true + }, + "normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "dev": true, + "requires": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + } + } + }, + "libtap": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/libtap/-/libtap-1.4.1.tgz", + "integrity": "sha512-S9v19shLTigoMn3c02V7LZ4t09zxmVP3r3RbEAwuHFYeKgF+ESFJxoQ0PMFKW4XdgQhcjVBEwDoopG6WROq/gw==", + "dev": true, + "requires": { + "async-hook-domain": "^2.0.4", + "bind-obj-methods": "^3.0.0", + "diff": "^4.0.2", + "function-loop": "^2.0.1", + "minipass": "^3.1.5", + "own-or": "^1.0.0", + "own-or-env": "^1.0.2", + "signal-exit": "^3.0.4", + "stack-utils": "^2.0.4", + "tap-parser": "^11.0.0", + "tap-yaml": "^1.0.0", + "tcompare": "^5.0.6", + "trivial-deferred": "^1.0.1" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "license-report": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/license-report/-/license-report-6.4.0.tgz", + "integrity": "sha512-JjY8aQRSu+Kx8BLhEH6ltylWDD66OkA875aFtGDJ4qILGRgIsFwfNx63bOrD6UGi7CNF9X/dd8I7l/PF4Kexjg==", + "dev": true, + "requires": { + "@kessler/tableify": "^1.0.2", + "debug": "^4.3.4", + "eol": "^0.9.1", + "got": "^12.6.0", + "rc": "^1.2.8", + "semver": "^7.3.8", + "tablemark": "^3.0.0", + "text-table": "^0.2.0", + "visit-values": "^2.0.0" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "lint-staged": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-11.2.6.tgz", + "integrity": "sha512-Vti55pUnpvPE0J9936lKl0ngVeTdSZpEdTNhASbkaWX7J5R9OEifo1INBGQuGW4zmy6OG+TcWPJ3m5yuy5Q8Tg==", + "dev": true, + "requires": { + "cli-truncate": "2.1.0", + "colorette": "^1.4.0", + "commander": "^8.2.0", + "cosmiconfig": "^7.0.1", + "debug": "^4.3.2", + "enquirer": "^2.3.6", + "execa": "^5.1.1", + "listr2": "^3.12.2", + "micromatch": "^4.0.4", + "normalize-path": "^3.0.0", + "please-upgrade-node": "^3.2.0", + "string-argv": "0.3.1", + "stringify-object": "3.3.0", + "supports-color": "8.1.1" + }, + "dependencies": { + "cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "dev": true, + "requires": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + } + } + }, + "load-json-file": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz", + "integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==", + "dev": true + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true + }, + "lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "dev": true + }, + "lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true + }, + "lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true + }, + "lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + } + } + }, + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, + "lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "requires": { + "semver": "^7.5.3" + } + }, + "make-dir-cli": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir-cli/-/make-dir-cli-3.1.0.tgz", + "integrity": "sha512-5GlL4/K4P2Ut2gAuGP2hwsJV/V69bvA1buKs32bCZztrcdq7lNOzviMJgWmZfDLBC6Ttfw/c7Y62MuPRfKdhlg==", + "dev": true, + "requires": { + "make-dir": "^4.0.0", + "meow": "^10.0.0" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "camelcase-keys": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", + "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", + "dev": true, + "requires": { + "camelcase": "^6.3.0", + "map-obj": "^4.1.0", + "quick-lru": "^5.1.1", + "type-fest": "^1.2.1" + } + }, + "decamelize": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", + "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", + "dev": true + }, + "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, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true + }, + "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, + "requires": { + "p-locate": "^5.0.0" + } + }, + "meow": { + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/meow/-/meow-10.1.5.tgz", + "integrity": "sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.2", + "camelcase-keys": "^7.0.0", + "decamelize": "^5.0.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.2", + "read-pkg-up": "^8.0.0", + "redent": "^4.0.0", + "trim-newlines": "^4.0.2", + "type-fest": "^1.2.2", + "yargs-parser": "^20.2.9" + } + }, + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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, + "requires": { + "p-limit": "^3.0.2" + } + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + }, + "read-pkg": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-6.0.0.tgz", + "integrity": "sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^3.0.2", + "parse-json": "^5.2.0", + "type-fest": "^1.0.1" + } + }, + "read-pkg-up": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-8.0.0.tgz", + "integrity": "sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==", + "dev": true, + "requires": { + "find-up": "^5.0.0", + "read-pkg": "^6.0.0", + "type-fest": "^1.0.1" + } + }, + "redent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-4.0.0.tgz", + "integrity": "sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==", + "dev": true, + "requires": { + "indent-string": "^5.0.0", + "strip-indent": "^4.0.0" + } + }, + "strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "dev": true, + "requires": { + "min-indent": "^1.0.1" + } + }, + "trim-newlines": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.1.1.tgz", + "integrity": "sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==", + "dev": true + }, + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dev": true, + "requires": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + } + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true + }, + "meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + } + }, + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "modify-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", + "dev": true + }, + "mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "multimatch": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-6.0.0.tgz", + "integrity": "sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ==", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.5", + "array-differ": "^4.0.0", + "array-union": "^3.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nested-error-stacks": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", + "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", + "dev": true + }, + "new-github-release-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/new-github-release-url/-/new-github-release-url-2.0.0.tgz", + "integrity": "sha512-NHDDGYudnvRutt/VhKFlX26IotXe1w0cmkDm6JGquh5bz/bDTw0LufSmH/GxTjEdpHEO+bVKFTwdrcGa/9XlKQ==", + "dev": true, + "requires": { + "type-fest": "^2.5.1" + }, + "dependencies": { + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true + } + } + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true + }, + "node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, + "node-gyp": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.0.tgz", + "integrity": "sha512-LkaKUbjyacJGRHiuhUeUblzZNxTF1/XNooyAl6aiaJ6ZpeurR4Mk9sjxncGNSI7pETqyqM+hLAER0788oSxt0A==", + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "dependencies": { + "isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true + }, + "which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "requires": { + "isexe": "^3.1.1" + } + } + } + }, + "node-gyp-build": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", + "dev": true + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node-polyfill-webpack-plugin": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-1.1.4.tgz", + "integrity": "sha512-Z0XTKj1wRWO8o/Vjobsw5iOJCN+Sua3EZEUc2Ziy9CyVvmHKu6o+t4gUH9GOE0czyPR94LI6ZCV/PpcM8b5yow==", + "dev": true, + "requires": { + "assert": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "console-browserify": "^1.2.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.12.0", + "domain-browser": "^4.19.0", + "events": "^3.3.0", + "filter-obj": "^2.0.2", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "punycode": "^2.1.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "timers-browserify": "^2.0.12", + "tty-browserify": "^0.0.1", + "url": "^0.11.0", + "util": "^0.12.4", + "vm-browserify": "^1.1.2" + } + }, + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "requires": { + "process-on-spawn": "^1.0.0" + } + }, + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "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 + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + }, + "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, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "nopt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "dev": true, + "requires": { + "abbrev": "^2.0.0" + } + }, + "normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true + }, + "npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^3.0.0" + } + }, + "npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true + }, + "npm-package-arg": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", + "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "dev": true, + "requires": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "requires": { + "lru-cache": "^10.0.1" + } + }, + "lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true + } + } + }, + "npm-packlist": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.0.tgz", + "integrity": "sha512-ErAGFB5kJUciPy1mmx/C2YFbvxoJ0QJ9uwkCZOeR6CqLLISPZBOiFModAbSXnjjlwW5lOhuhXva+fURsSGJqyw==", + "dev": true, + "requires": { + "ignore-walk": "^6.0.0" + } + }, + "npm-pick-manifest": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", + "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", + "dev": true, + "requires": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + } + }, + "npm-registry-fetch": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", + "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", + "dev": true, + "requires": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + } + }, + "npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^1.9.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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, + "requires": { + "color-name": "1.1.3" + } + }, + "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 + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "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 + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "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, + "requires": { + "has-flag": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "npm-watch": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/npm-watch/-/npm-watch-0.11.0.tgz", + "integrity": "sha512-wAOd0moNX2kSA2FNvt8+7ORwYaJpQ1ZoWjUYdb1bBCxq4nkWuU0IiJa9VpVxrj5Ks+FGXQd62OC/Bjk0aSr+dg==", + "dev": true, + "requires": { + "nodemon": "^2.0.7", + "through2": "^4.0.2" + } + }, + "npmlog": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-7.0.1.tgz", + "integrity": "sha512-uJ0YFk/mCQpLBt+bxN88AKd+gyqZvZDbtiNxk6Waqcj2aPRyfVx8ITawkyQynxUagInjdYT1+qj4NfA5KJJUxg==", + "dev": true, + "requires": { + "are-we-there-yet": "^4.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^5.0.0", + "set-blocking": "^2.0.0" + } + }, + "nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, + "object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "dev": true + }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true + }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + } + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "own-or": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/own-or/-/own-or-1.0.0.tgz", + "integrity": "sha512-NfZr5+Tdf6MB8UI9GLvKRs4cXY8/yB0w3xtt84xFdWy8hkGjn+JFc60VhzS/hFRfbyxFcGYMTjnF4Me+RbbqrA==", + "dev": true + }, + "own-or-env": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/own-or-env/-/own-or-env-1.0.2.tgz", + "integrity": "sha512-NQ7v0fliWtK7Lkb+WdFqe6ky9XAzYmlkXthQrBbzlYbmFKoAYbDDcwmOm6q8kOuwSRXW8bdL5ORksploUJmWgw==", + "dev": true, + "requires": { + "own-or": "^1.0.0" + } + }, + "p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true + }, + "p-event": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", + "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "dev": true, + "requires": { + "p-timeout": "^3.1.0" + }, + "dependencies": { + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + } + } + }, + "p-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-3.0.0.tgz", + "integrity": "sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==", + "dev": true, + "requires": { + "p-map": "^5.1.0" + }, + "dependencies": { + "aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "requires": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + } + }, + "clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "dev": true, + "requires": { + "escape-string-regexp": "5.0.0" + } + }, + "escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true + }, + "indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true + }, + "p-map": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", + "dev": true, + "requires": { + "aggregate-error": "^4.0.0" + } + } + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-6.0.0.tgz", + "integrity": "sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==", + "dev": true + }, + "p-pipe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-4.0.0.tgz", + "integrity": "sha512-HkPfFklpZQPUKBFXzKFB6ihLriIHxnmuQdK9WmLDwe4hf2PdhhfWT/FJa+pc3bA1ywvKXtedxIRmd4Y7BTXE4w==", + "dev": true + }, + "p-queue": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-7.4.1.tgz", + "integrity": "sha512-vRpMXmIkYF2/1hLBKisKeVYJZ8S2tZ0zEAmIJgdVKP2nq0nh4qCdf8bgw+ZgKrkh71AOCaqzwbJJk1WtdcF3VA==", + "dev": true, + "requires": { + "eventemitter3": "^5.0.1", + "p-timeout": "^5.0.2" + } + }, + "p-reduce": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", + "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", + "dev": true + }, + "p-timeout": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz", + "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==", + "dev": true + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "pacote": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.4.tgz", + "integrity": "sha512-eGdLHrV/g5b5MtD5cTPyss+JxOlaOloSMG3UwPMAvL8ywaLJ6beONPF40K4KKl/UI6q5hTKCJq5rCu8tkF+7Dg==", + "dev": true, + "requires": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-conflict-json": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-3.0.1.tgz", + "integrity": "sha512-01TvEktc68vwbJOtWZluyWeVGWjP+bZwXtPDMQVbBKzbJ/vZBif0L69KH1+cHv1SZ6e0FKLvjyHe8mqsIqYOmw==", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "dependencies": { + "json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true + } + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse-path": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.0.0.tgz", + "integrity": "sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==", + "dev": true, + "requires": { + "protocols": "^2.0.0" + } + }, + "parse-url": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-8.1.0.tgz", + "integrity": "sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==", + "dev": true, + "requires": { + "parse-path": "^7.0.0" + } + }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "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 + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "requires": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true + } + } + }, + "path-to-regexp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", + "integrity": "sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "dev": true + }, + "pify": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-6.1.0.tgz", + "integrity": "sha512-KocF8ve28eFjjuBKKGvzOBGzG8ew2OqOOSxTTZhirkzH7h3BI1vyzqlR0qbfcDBve1Yzo3FVlWUAtCRrbVN8Fw==", + "dev": true + }, + "pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "requires": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise-all-reject-late": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", + "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "dev": true + }, + "promise-call-limit": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-1.0.2.tgz", + "integrity": "sha512-1vTUnfI2hzui8AEIixbdAJlFY4LFDXqQswy/2eOlThAscXCY4It8FdVuI0fMJGAB2aWGbdQf/gv0skKYXmdrHA==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, + "protoc-gen-ts": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/protoc-gen-ts/-/protoc-gen-ts-0.8.6.tgz", + "integrity": "sha512-66oeorGy4QBvYjQGd/gaeOYyFqKyRmRgTpofmnw8buMG0P7A0jQjoKSvKJz5h5tNUaVkIzvGBUTRVGakrhhwpA==", + "dev": true + }, + "protocols": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.1.tgz", + "integrity": "sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==", + "dev": true + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + }, + "pure-rand": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", + "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "dev": true + }, + "qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true + } + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "read-cmd-shim": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-4.0.0.tgz", + "integrity": "sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==", + "dev": true + }, + "read-package-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz", + "integrity": "sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg==", + "dev": true, + "requires": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "requires": { + "lru-cache": "^10.0.1" + } + }, + "json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true + }, + "lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true + }, + "normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "dev": true, + "requires": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + } + } + }, + "read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "dependencies": { + "json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true + } + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true + }, + "regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-global": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-global/-/resolve-global-1.0.0.tgz", + "integrity": "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==", + "dev": true, + "requires": { + "global-dirs": "^0.1.1" + } + }, + "resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true + }, + "responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "requires": { + "lowercase-keys": "^3.0.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "run-time-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/run-time-error/-/run-time-error-1.4.0.tgz", + "integrity": "sha512-eYJ8Uws3zU7gU7dbKZg5vKIEvl8025pVpTkgU6Up8wSGyOo6MRUCJ0qFi1EY2wgQDyX/DvXaQncK/nlho//Bxw==", + "dev": true + }, + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "requires": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true + }, + "semver-parser": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/semver-parser/-/semver-parser-4.1.4.tgz", + "integrity": "sha512-U0IqwT7n99QS5/L8erhYGXBiiZH4M8t6YIlUuloY+mZpXkQOmH0V7Xf5oMytTpasjCjJCbrfysK01fIRbyDyrQ==", + "dev": true + }, + "sentence-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", + "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "requires": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "requires": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-loader": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shebang-loader/-/shebang-loader-0.0.1.tgz", + "integrity": "sha512-nQvhUHvKyzGK5aqPxHfHB5nlAN2EZ2U61S2G0YrxAuCRU5iGhFcxxRiaAdb18UoRS1zVMhRz4gdQ1xFEg3AOyA==", + "dev": true + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "sigstore": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.1.0.tgz", + "integrity": "sha512-kPIj+ZLkyI3QaM0qX8V/nSsweYND3W448pwkDgS6CQ74MfhEkIR8ToK5Iyx46KJYRjseVcD3Rp9zAmUAj6ZjPw==", + "dev": true, + "requires": { + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/sign": "^2.1.0", + "@sigstore/tuf": "^2.1.0" + } + }, + "simple-git": { + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.19.1.tgz", + "integrity": "sha512-Ck+rcjVaE1HotraRAS8u/+xgTvToTuoMkT9/l9lvuP5jftwnYUp6DwuJzsKErHgfyRk8IB8pqGHWEbM3tLgV1w==", + "dev": true, + "requires": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.4" + } + }, + "simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "requires": { + "semver": "~7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "sirv": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", + "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "dev": true, + "requires": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^1.0.0" + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", + "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "dev": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + } + }, + "sort-keys": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-5.0.0.tgz", + "integrity": "sha512-Pdz01AvCAottHTPQGzndktFNdbRA75BgOfeT1hH+AMnJFv8lynkPi42rfeEhpx1saTEI3YNMWxfqu0sFD1G8pw==", + "dev": true, + "requires": { + "is-plain-obj": "^4.0.0" + }, + "dependencies": { + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true + } + } + }, + "sort-object-keys": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.3.tgz", + "integrity": "sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==", + "dev": true + }, + "sort-package-json": { + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.57.0.tgz", + "integrity": "sha512-FYsjYn2dHTRb41wqnv+uEqCUvBpK3jZcTp9rbz2qDTmel7Pmdtf+i2rLaaPMRZeSVM60V3Se31GyWFpmKs4Q5Q==", + "dev": true, + "requires": { + "detect-indent": "^6.0.0", + "detect-newline": "3.1.0", + "git-hooks-list": "1.0.3", + "globby": "10.0.0", + "is-plain-obj": "2.1.0", + "sort-object-keys": "^1.1.3" + }, + "dependencies": { + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globby": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.0.tgz", + "integrity": "sha512-3LifW9M4joGZasyYPz2A1U74zbC/45fvpXUvO/9KbSa+VV0aGZarWkfdgKyR9sExNP0t0x0ss/UMJpNpcaTspw==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "source-map-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", + "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" + } + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", + "dev": true + }, + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "requires": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "dependencies": { + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "requires": { + "through": "2" + } + }, + "split-text-to-chunks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/split-text-to-chunks/-/split-text-to-chunks-1.0.0.tgz", + "integrity": "sha512-HLtEwXK/T4l7QZSJ/kOSsZC0o5e2Xg3GzKKFxm0ZexJXw0Bo4CaEl39l7MCSRHk9EOOL5jT8JIDjmhTtcoe6lQ==", + "dev": true, + "requires": { + "get-stdin": "^5.0.1", + "minimist": "^1.2.0" + }, + "dependencies": { + "get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha512-jZV7n6jGE3Gt7fgSTJoz91Ak5MuTLwMwkoYdjxuJ/AmjIsE1UC03y/IWkZCQGEvVNS9qoRNwy5BCqxImv0FVeA==", + "dev": true + } + } + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "requires": { + "readable-stream": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dev": true, + "requires": { + "minipass": "^7.0.3" + } + }, + "stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "requires": { + "internal-slot": "^1.0.4" + } + }, + "stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "requires": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "string-argv": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", + "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "dev": true + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.padend": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.5.tgz", + "integrity": "sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "dependencies": { + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "dev": true + } + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "strong-log-transformer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", + "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "minimist": "^1.2.0", + "through": "^2.3.4" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + } + }, + "tablemark": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tablemark/-/tablemark-3.0.0.tgz", + "integrity": "sha512-7N05gRK7t6B4g8AtedUsKoKtPjplmUjOPr/V4kVB+7U3yGiB3WvKqMTTQzVCZyhfZUXgQFp9YyN9ZgC52uCPKw==", + "dev": true, + "requires": { + "sentence-case": "^3.0.4", + "split-text-to-chunks": "^1.0.0" + } + }, + "tap": { + "version": "16.3.8", + "resolved": "https://registry.npmjs.org/tap/-/tap-16.3.8.tgz", + "integrity": "sha512-ARpCLtOFST37MholnZm7JMFikGq0x/T9uBdZH83iuddPNgwDTZQiD8+4x7VABUfVWS0ozKUkmHZ5OOzMI3fLPg==", + "dev": true, + "requires": { + "@isaacs/import-jsx": "^4.0.1", + "@types/react": "^17.0.52", + "chokidar": "^3.3.0", + "findit": "^2.0.0", + "foreground-child": "^2.0.0", + "fs-exists-cached": "^1.0.0", + "glob": "^7.2.3", + "ink": "^3.2.0", + "isexe": "^2.0.0", + "istanbul-lib-processinfo": "^2.0.3", + "jackspeak": "^1.4.2", + "libtap": "^1.4.0", + "minipass": "^3.3.4", + "mkdirp": "^1.0.4", + "nyc": "^15.1.0", + "opener": "^1.5.1", + "react": "^17.0.2", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.6", + "source-map-support": "^0.5.16", + "tap-mocha-reporter": "^5.0.3", + "tap-parser": "^11.0.2", + "tap-yaml": "^1.0.2", + "tcompare": "^5.0.7", + "treport": "^3.0.4", + "which": "^2.0.2" + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/highlight": "^7.22.5" + } + }, + "@babel/compat-data": { + "version": "7.22.9", + "bundled": true, + "dev": true + }, + "@babel/core": { + "version": "7.22.9", + "bundled": true, + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.1" + } + }, + "@babel/generator": { + "version": "7.22.9", + "bundled": true, + "dev": true, + "requires": { + "@babel/types": "^7.22.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.9", + "bundled": true, + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "bundled": true, + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.22.9", + "bundled": true, + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.22.5", + "bundled": true, + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "bundled": true, + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "bundled": true, + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.5", + "bundled": true, + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.22.5", + "bundled": true, + "dev": true + }, + "@babel/helpers": { + "version": "7.22.6", + "bundled": true, + "dev": true, + "requires": { + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5" + } + }, + "@babel/highlight": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.22.7", + "bundled": true, + "dev": true + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "bundled": true, + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "bundled": true, + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/template": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/traverse": { + "version": "7.22.8", + "bundled": true, + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.7", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/types": "^7.22.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.22.5", + "bundled": true, + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "to-fast-properties": "^2.0.0" + } + }, + "@isaacs/import-jsx": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "requires": { + "@babel/core": "^7.5.5", + "@babel/plugin-proposal-object-rest-spread": "^7.5.5", + "@babel/plugin-transform-destructuring": "^7.5.0", + "@babel/plugin-transform-react-jsx": "^7.3.0", + "caller-path": "^3.0.1", + "find-cache-dir": "^3.2.0", + "make-dir": "^3.0.2", + "resolve-from": "^3.0.0", + "rimraf": "^3.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "bundled": true, + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "bundled": true, + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "bundled": true, + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.18", + "bundled": true, + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + }, + "dependencies": { + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "bundled": true, + "dev": true + } + } + }, + "@types/prop-types": { + "version": "15.7.5", + "bundled": true, + "dev": true + }, + "@types/react": { + "version": "17.0.62", + "bundled": true, + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/scheduler": { + "version": "0.16.3", + "bundled": true, + "dev": true + }, + "@types/yoga-layout": { + "version": "1.9.2", + "bundled": true, + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "bundled": true, + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "bundled": true, + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "auto-bind": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browserslist": { + "version": "4.21.9", + "bundled": true, + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001503", + "electron-to-chromium": "^1.4.431", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" + } + }, + "caller-callsite": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "callsites": "^3.1.0" + } + }, + "caller-path": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "caller-callsite": "^4.1.0" + } + }, + "callsites": { + "version": "3.1.0", + "bundled": true, + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001517", + "bundled": true, + "dev": true + }, + "cardinal": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + } + }, + "chalk": { + "version": "2.4.2", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "ci-info": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "bundled": true, + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-truncate": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "code-excerpt": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "convert-to-spaces": "^1.0.1" + } + }, + "color-convert": { + "version": "1.9.3", + "bundled": true, + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "commondir": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "convert-source-map": { + "version": "1.9.0", + "bundled": true, + "dev": true + }, + "convert-to-spaces": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "csstype": { + "version": "3.1.2", + "bundled": true, + "dev": true + }, + "debug": { + "version": "4.3.4", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "electron-to-chromium": { + "version": "1.4.477", + "bundled": true, + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "bundled": true, + "dev": true + }, + "escalade": { + "version": "3.1.1", + "bundled": true, + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "esprima": { + "version": "4.0.1", + "bundled": true, + "dev": true + }, + "events-to-array": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "find-cache-dir": { + "version": "3.3.2", + "bundled": true, + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "bundled": true, + "dev": true + }, + "glob": { + "version": "7.2.3", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "bundled": true, + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "ink": { + "version": "3.2.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "auto-bind": "4.0.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.0", + "cli-cursor": "^3.1.0", + "cli-truncate": "^2.1.0", + "code-excerpt": "^3.0.0", + "indent-string": "^4.0.0", + "is-ci": "^2.0.0", + "lodash": "^4.17.20", + "patch-console": "^1.0.0", + "react-devtools-core": "^4.19.1", + "react-reconciler": "^0.26.2", + "scheduler": "^0.20.2", + "signal-exit": "^3.0.2", + "slice-ansi": "^3.0.0", + "stack-utils": "^2.0.2", + "string-width": "^4.2.2", + "type-fest": "^0.12.0", + "widest-line": "^3.1.0", + "wrap-ansi": "^6.2.0", + "ws": "^7.5.5", + "yoga-layout-prebuilt": "^1.9.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "bundled": true, + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "is-ci": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "jackspeak": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.2.tgz", + "integrity": "sha512-GHeGTmnuaHnvS+ZctRB01bfxARuu9wW83ENbuiweu07SFcVlZrJpcshSre/keGT7YGBhLHg/+rXCNSrsEHKU4Q==", + "dev": true, + "requires": { + "cliui": "^7.0.4" + } + }, + "js-tokens": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "bundled": true, + "dev": true + }, + "json5": { + "version": "2.2.3", + "bundled": true, + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "bundled": true, + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minipass": { + "version": "3.3.6", + "bundled": true, + "dev": true, + "requires": { + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "bundled": true, + "dev": true + } + } + }, + "ms": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, + "node-releases": { + "version": "2.0.13", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "patch-console": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "bundled": true, + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "punycode": { + "version": "2.3.0", + "bundled": true, + "dev": true + }, + "react": { + "version": "17.0.2", + "bundled": true, + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "react-devtools-core": { + "version": "4.28.0", + "bundled": true, + "dev": true, + "requires": { + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, + "react-reconciler": { + "version": "0.26.2", + "bundled": true, + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + } + }, + "redeyed": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "esprima": "~4.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "rimraf": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "scheduler": { + "version": "0.20.2", + "bundled": true, + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "semver": { + "version": "6.3.1", + "bundled": true, + "dev": true + }, + "shell-quote": { + "version": "1.8.1", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.7", + "bundled": true, + "dev": true + }, + "slice-ansi": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "bundled": true, + "dev": true + } + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "stack-utils": { + "version": "2.0.6", + "bundled": true, + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "bundled": true, + "dev": true + } + } + }, + "string-width": { + "version": "4.2.3", + "bundled": true, + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "5.5.0", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tap-parser": { + "version": "11.0.2", + "bundled": true, + "dev": true, + "requires": { + "events-to-array": "^1.0.1", + "minipass": "^3.1.6", + "tap-yaml": "^1.0.0" + } + }, + "tap-yaml": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "yaml": "^1.10.2" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "treport": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "@isaacs/import-jsx": "^4.0.1", + "cardinal": "^2.1.1", + "chalk": "^3.0.0", + "ink": "^3.2.0", + "ms": "^2.1.2", + "tap-parser": "^11.0.0", + "tap-yaml": "^1.0.0", + "unicode-length": "^2.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "bundled": true, + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "type-fest": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "unicode-length": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "punycode": "^2.0.0" + } + }, + "update-browserslist-db": { + "version": "1.0.11", + "bundled": true, + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "widest-line": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "bundled": true, + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "ws": { + "version": "7.5.9", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.1.1", + "bundled": true, + "dev": true + }, + "yaml": { + "version": "1.10.2", + "bundled": true, + "dev": true + }, + "yoga-layout-prebuilt": { + "version": "1.10.0", + "bundled": true, + "dev": true, + "requires": { + "@types/yoga-layout": "1.9.2" + } + } + } + }, + "tap-mocha-reporter": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-5.0.4.tgz", + "integrity": "sha512-J+YMO8B7lq1O6Zxd/jeuG27vJ+Y4tLiRMKPSb7KR6FVh86k3Rq1TwYc2GKPyIjCbzzdMdReh3Vfz9L5cg1Z2Bw==", + "dev": true, + "requires": { + "color-support": "^1.1.0", + "debug": "^4.1.1", + "diff": "^4.0.1", + "escape-string-regexp": "^2.0.0", + "glob": "^7.0.5", + "tap-parser": "^11.0.0", + "tap-yaml": "^1.0.0", + "unicode-length": "^2.0.2" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "tap-parser": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-11.0.2.tgz", + "integrity": "sha512-6qGlC956rcORw+fg7Fv1iCRAY8/bU9UabUAhs3mXRH6eRmVZcNPLheSXCYaVaYeSwx5xa/1HXZb1537YSvwDZg==", + "dev": true, + "requires": { + "events-to-array": "^1.0.1", + "minipass": "^3.1.6", + "tap-yaml": "^1.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "tap-yaml": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.2.tgz", + "integrity": "sha512-GegASpuqBnRNdT1U+yuUPZ8rEU64pL35WPBpCISWwff4dErS2/438barz7WFJl4Nzh3Y05tfPidZnH+GaV1wMg==", + "dev": true, + "requires": { + "yaml": "^1.10.2" + } + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "tape": { + "version": "5.6.6", + "resolved": "https://registry.npmjs.org/tape/-/tape-5.6.6.tgz", + "integrity": "sha512-rGp2cZ3rfZ6QfTBm6yvohf8aXmDqPyzMKZwTMV12w4i+b/N2Adwlg8PlW8jLqWzlJUZhglyYaLOSrMt/ZlZkAA==", + "dev": true, + "requires": { + "@ljharb/resumer": "^0.0.1", + "@ljharb/through": "^2.3.9", + "array.prototype.every": "^1.1.4", + "call-bind": "^1.0.2", + "deep-equal": "^2.2.2", + "defined": "^1.0.1", + "dotignore": "^0.1.2", + "for-each": "^0.3.3", + "get-package-type": "^0.1.0", + "glob": "^7.2.3", + "has": "^1.0.3", + "has-dynamic-import": "^2.0.1", + "inherits": "^2.0.4", + "is-regex": "^1.1.4", + "minimist": "^1.2.8", + "object-inspect": "^1.12.3", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "resolve": "^2.0.0-next.4", + "string.prototype.trim": "^1.2.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "tape-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tape-promise/-/tape-promise-4.0.0.tgz", + "integrity": "sha512-mNi5yhWAKDuNgZCfFKeZbsXvraVOf+I8UZG+lf+aoRrzX4+jd4mpNBjYh16/VcpEMUtS0iFndBgnfxxZbtyLFw==", + "dev": true, + "requires": { + "is-promise": "^2.1.0", + "onetime": "^2.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + } + } + }, + "tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true + } + } + }, + "tcompare": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-5.0.7.tgz", + "integrity": "sha512-d9iddt6YYGgyxJw5bjsN7UJUO1kGOtjSlNy/4PoGYAjQS5pAT/hzIoLf1bZCw+uUxRmZJh7Yy1aA7xKVRT9B4w==", + "dev": true, + "requires": { + "diff": "^4.0.2" + } + }, + "temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "dev": true + }, + "terser": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.22.0.tgz", + "integrity": "sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "text-extensions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "requires": { + "readable-stream": "3" + } + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "dev": true + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "treeverse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-3.0.0.tgz", + "integrity": "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==", + "dev": true + }, + "trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true + }, + "trivial-deferred": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-1.1.2.tgz", + "integrity": "sha512-vDPiDBC3hyP6O4JrJYMImW3nl3c03Tsj9fEXc7Qc/XKa1O7gf5ZtFfIR/E0dun9SnDHdwjna1Z2rSzYgqpxh/g==", + "dev": true + }, + "ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true + }, + "ts-jest": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "dependencies": { + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, + "ts-loader": { + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.4.tgz", + "integrity": "sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + } + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "dev": true + }, + "tuf-js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.1.0.tgz", + "integrity": "sha512-eD7YPPjVlMzdggrOeE8zwoegUaG/rt6Bt3jwoQPunRiNVzgcCE009UDFJKJjG+Gk9wFu6W/Vi+P5d/5QpdD9jA==", + "dev": true, + "requires": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + } + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true + }, + "typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true + }, + "uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true + }, + "uid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.1.tgz", + "integrity": "sha512-PF+1AnZgycpAIEmNtjxGBVmKbZAQguaa4pBUq6KNaGEcpzZ2klCNZLM34tsjp76maN00TttiiUf6zkIBpJQm2A==", + "dev": true, + "requires": { + "@lukeed/csprng": "^1.0.0" + } + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "unicode-length": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-length/-/unicode-length-2.1.0.tgz", + "integrity": "sha512-4bV582zTV9Q02RXBxSUMiuN/KHo5w4aTojuKTNT96DIKps/SIawFp7cS5Mu25VuY1AioGXrmYyzKZUzh8OqoUw==", + "dev": true, + "requires": { + "punycode": "^2.0.0" + } + }, + "unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "requires": { + "unique-slug": "^4.0.0" + } + }, + "unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "dev": true + }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "upper-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", + "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.3.tgz", + "integrity": "sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==", + "dev": true, + "requires": { + "punycode": "^1.4.1", + "qs": "^6.11.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true + } + } + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "v8-to-istanbul": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", + "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + }, + "visit-values": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/visit-values/-/visit-values-2.0.0.tgz", + "integrity": "sha512-vLFU70y3D915d611GnHYeHkEmq6ZZETzTH4P1hM6I9E3lBwH2VeBBEESe/bGCY+gAyK0qqLFn5bNFpui/GKmww==", + "dev": true + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "vscode-languageserver-textdocument": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", + "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==", + "dev": true + }, + "vscode-uri": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", + "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==", + "dev": true + }, + "walk-up-path": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-3.0.1.tgz", + "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", + "dev": true + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true + }, + "web3": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/web3/-/web3-4.1.1.tgz", + "integrity": "sha512-vnPll2G+ZNktSu7oJVjAW0QYuY0kPHLs8LQMifml4kTR+hqhiTmzMIzO8FqkcsESLEu6H9R7Acj6EgyeU1hruQ==", + "dev": true, + "requires": { + "web3-core": "^4.1.1", + "web3-errors": "^1.1.1", + "web3-eth": "^4.1.1", + "web3-eth-abi": "^4.1.1", + "web3-eth-accounts": "^4.0.5", + "web3-eth-contract": "^4.0.5", + "web3-eth-ens": "^4.0.5", + "web3-eth-iban": "^4.0.5", + "web3-eth-personal": "^4.0.5", + "web3-net": "^4.0.5", + "web3-providers-http": "^4.0.5", + "web3-providers-ws": "^4.0.5", + "web3-rpc-methods": "^1.1.1", + "web3-types": "^1.1.1", + "web3-utils": "^4.0.5", + "web3-validator": "^2.0.1" + } + }, + "web3-core": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-4.1.1.tgz", + "integrity": "sha512-wzS01bC+ihf5DJ6mz2fz4d5yxnPEM5AYQIRihO8kUt3dil+X4V07CHks23wLbb9yk8U9+3a1Iod207WGF872rA==", + "dev": true, + "requires": { + "web3-errors": "^1.1.1", + "web3-eth-iban": "^4.0.5", + "web3-providers-http": "^4.0.5", + "web3-providers-ipc": "^4.0.5", + "web3-providers-ws": "^4.0.5", + "web3-types": "^1.1.1", + "web3-utils": "^4.0.5", + "web3-validator": "^2.0.1" + } + }, + "web3-errors": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/web3-errors/-/web3-errors-1.1.3.tgz", + "integrity": "sha512-3GA4leG6XsKLmFWe62mIjVgW4GhkJmvd4IaRLgnKtNnqNmx6L9YWysYwgQ09BaD/NmhKN+AtalSVRds8gU+N0w==", + "dev": true, + "requires": { + "web3-types": "^1.3.0" + } + }, + "web3-eth": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-4.1.1.tgz", + "integrity": "sha512-0lftXINbeEOiYhHCWIKgeAOPnjoeHR8DTWLOjURDoz5CKbTj2wfcRQvuL6tUfvvVmrGWHEfIOncM30jhjlTxYQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.5", + "web3-core": "^4.1.1", + "web3-errors": "^1.1.1", + "web3-eth-abi": "^4.1.1", + "web3-eth-accounts": "^4.0.5", + "web3-net": "^4.0.5", + "web3-providers-ws": "^4.0.5", + "web3-rpc-methods": "^1.1.1", + "web3-types": "^1.1.1", + "web3-utils": "^4.0.5", + "web3-validator": "^2.0.1" + } + }, + "web3-eth-abi": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-4.1.4.tgz", + "integrity": "sha512-YLOBVVxxxLYKXjaiwZjEWYEnkMmmrm0nswZsvzSsINy/UgbWbzfoiZU+zn4YNWIEhORhx1p37iS3u/dP6VyC2w==", + "dev": true, + "requires": { + "abitype": "0.7.1", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + }, + "dependencies": { + "web3-utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.7.tgz", + "integrity": "sha512-sy8S6C2FIa5NNHc8DjND+Fx3S8KDAizuh5RbL1RX3h0PRbFgPfWzF5RfUns8gTt0mjJuOhs/IaDhrZfeTszG5A==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + } + } + } + }, + "web3-eth-accounts": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-4.1.0.tgz", + "integrity": "sha512-UFtAsOANsvihTQ6SSvOKguupmQkResyR9M9JNuOxYpKh7+3W+sTnbLXw2UbOSYIsKlc1mpqqW9bVr1SjqHDpUQ==", + "dev": true, + "requires": { + "@ethereumjs/rlp": "^4.0.1", + "crc-32": "^1.2.2", + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + }, + "dependencies": { + "web3-utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.7.tgz", + "integrity": "sha512-sy8S6C2FIa5NNHc8DjND+Fx3S8KDAizuh5RbL1RX3h0PRbFgPfWzF5RfUns8gTt0mjJuOhs/IaDhrZfeTszG5A==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + } + } + } + }, + "web3-eth-contract": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-4.1.2.tgz", + "integrity": "sha512-kVcMIurY4buNOfVhuE1Gg8NmSo5EmAOgBwECwU6lE8xUkbWAC6nhJGX1fgZjoC075HnSr89G1zgwlePyEdC0wQ==", + "dev": true, + "requires": { + "web3-core": "^4.3.0", + "web3-errors": "^1.1.3", + "web3-eth": "^4.3.1", + "web3-eth-abi": "^4.1.4", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + }, + "dependencies": { + "web3-core": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-4.3.0.tgz", + "integrity": "sha512-//cy1W780nkMXd/9g2+GIa7KlHMuE+PJPhPD4NdwpUxvtQni6GkXSxtFnImZufyGVP+BpO5g7QneiSeu5ce+IQ==", + "dev": true, + "requires": { + "web3-errors": "^1.1.3", + "web3-eth-iban": "^4.0.7", + "web3-providers-http": "^4.1.0", + "web3-providers-ipc": "^4.0.7", + "web3-providers-ws": "^4.0.7", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + } + }, + "web3-eth": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-4.3.1.tgz", + "integrity": "sha512-zJir3GOXooHQT85JB8SrufE+Voo5TtXdjhf1D8IGXmxM8MrhI8AT+Pgt4siBTupJcu5hF17iGmTP/Nj2XnaibQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.5", + "web3-core": "^4.3.0", + "web3-errors": "^1.1.3", + "web3-eth-abi": "^4.1.4", + "web3-eth-accounts": "^4.1.0", + "web3-net": "^4.0.7", + "web3-providers-ws": "^4.0.7", + "web3-rpc-methods": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + } + }, + "web3-utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.7.tgz", + "integrity": "sha512-sy8S6C2FIa5NNHc8DjND+Fx3S8KDAizuh5RbL1RX3h0PRbFgPfWzF5RfUns8gTt0mjJuOhs/IaDhrZfeTszG5A==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + } + } + } + }, + "web3-eth-ens": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-4.0.8.tgz", + "integrity": "sha512-nj0JfeD45BbzVJcVYpUJnSo8iwDcY9CQ7CZhhIVVOFjvpMAPw0zEwjTvZEIQyCW61OoDG9xcBzwxe2tZoYhMRw==", + "dev": true, + "requires": { + "@adraffy/ens-normalize": "^1.8.8", + "web3-core": "^4.3.0", + "web3-errors": "^1.1.3", + "web3-eth": "^4.3.1", + "web3-eth-contract": "^4.1.2", + "web3-net": "^4.0.7", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + }, + "dependencies": { + "web3-core": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-4.3.0.tgz", + "integrity": "sha512-//cy1W780nkMXd/9g2+GIa7KlHMuE+PJPhPD4NdwpUxvtQni6GkXSxtFnImZufyGVP+BpO5g7QneiSeu5ce+IQ==", + "dev": true, + "requires": { + "web3-errors": "^1.1.3", + "web3-eth-iban": "^4.0.7", + "web3-providers-http": "^4.1.0", + "web3-providers-ipc": "^4.0.7", + "web3-providers-ws": "^4.0.7", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + } + }, + "web3-eth": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-4.3.1.tgz", + "integrity": "sha512-zJir3GOXooHQT85JB8SrufE+Voo5TtXdjhf1D8IGXmxM8MrhI8AT+Pgt4siBTupJcu5hF17iGmTP/Nj2XnaibQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.5", + "web3-core": "^4.3.0", + "web3-errors": "^1.1.3", + "web3-eth-abi": "^4.1.4", + "web3-eth-accounts": "^4.1.0", + "web3-net": "^4.0.7", + "web3-providers-ws": "^4.0.7", + "web3-rpc-methods": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + } + }, + "web3-utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.7.tgz", + "integrity": "sha512-sy8S6C2FIa5NNHc8DjND+Fx3S8KDAizuh5RbL1RX3h0PRbFgPfWzF5RfUns8gTt0mjJuOhs/IaDhrZfeTszG5A==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + } + } + } + }, + "web3-eth-iban": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-4.0.7.tgz", + "integrity": "sha512-8weKLa9KuKRzibC87vNLdkinpUE30gn0IGY027F8doeJdcPUfsa4IlBgNC4k4HLBembBB2CTU0Kr/HAOqMeYVQ==", + "dev": true, + "requires": { + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + }, + "dependencies": { + "web3-utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.7.tgz", + "integrity": "sha512-sy8S6C2FIa5NNHc8DjND+Fx3S8KDAizuh5RbL1RX3h0PRbFgPfWzF5RfUns8gTt0mjJuOhs/IaDhrZfeTszG5A==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + } + } + } + }, + "web3-eth-personal": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-4.0.8.tgz", + "integrity": "sha512-sXeyLKJ7ddQdMxz1BZkAwImjqh7OmKxhXoBNF3isDmD4QDpMIwv/t237S3q4Z0sZQamPa/pHebJRWVuvP8jZdw==", + "dev": true, + "requires": { + "web3-core": "^4.3.0", + "web3-eth": "^4.3.1", + "web3-rpc-methods": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + }, + "dependencies": { + "web3-core": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-4.3.0.tgz", + "integrity": "sha512-//cy1W780nkMXd/9g2+GIa7KlHMuE+PJPhPD4NdwpUxvtQni6GkXSxtFnImZufyGVP+BpO5g7QneiSeu5ce+IQ==", + "dev": true, + "requires": { + "web3-errors": "^1.1.3", + "web3-eth-iban": "^4.0.7", + "web3-providers-http": "^4.1.0", + "web3-providers-ipc": "^4.0.7", + "web3-providers-ws": "^4.0.7", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + } + }, + "web3-eth": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-4.3.1.tgz", + "integrity": "sha512-zJir3GOXooHQT85JB8SrufE+Voo5TtXdjhf1D8IGXmxM8MrhI8AT+Pgt4siBTupJcu5hF17iGmTP/Nj2XnaibQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.5", + "web3-core": "^4.3.0", + "web3-errors": "^1.1.3", + "web3-eth-abi": "^4.1.4", + "web3-eth-accounts": "^4.1.0", + "web3-net": "^4.0.7", + "web3-providers-ws": "^4.0.7", + "web3-rpc-methods": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + } + }, + "web3-utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.7.tgz", + "integrity": "sha512-sy8S6C2FIa5NNHc8DjND+Fx3S8KDAizuh5RbL1RX3h0PRbFgPfWzF5RfUns8gTt0mjJuOhs/IaDhrZfeTszG5A==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + } + } + } + }, + "web3-net": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-4.0.7.tgz", + "integrity": "sha512-SzEaXFrBjY25iQGk5myaOfO9ZyfTwQEa4l4Ps4HDNVMibgZji3WPzpjq8zomVHMwi8bRp6VV7YS71eEsX7zLow==", + "dev": true, + "requires": { + "web3-core": "^4.3.0", + "web3-rpc-methods": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7" + }, + "dependencies": { + "web3-core": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-4.3.0.tgz", + "integrity": "sha512-//cy1W780nkMXd/9g2+GIa7KlHMuE+PJPhPD4NdwpUxvtQni6GkXSxtFnImZufyGVP+BpO5g7QneiSeu5ce+IQ==", + "dev": true, + "requires": { + "web3-errors": "^1.1.3", + "web3-eth-iban": "^4.0.7", + "web3-providers-http": "^4.1.0", + "web3-providers-ipc": "^4.0.7", + "web3-providers-ws": "^4.0.7", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + } + }, + "web3-utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.7.tgz", + "integrity": "sha512-sy8S6C2FIa5NNHc8DjND+Fx3S8KDAizuh5RbL1RX3h0PRbFgPfWzF5RfUns8gTt0mjJuOhs/IaDhrZfeTszG5A==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + } + } + } + }, + "web3-providers-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-4.1.0.tgz", + "integrity": "sha512-6qRUGAhJfVQM41E5t+re5IHYmb5hSaLc02BE2MaRQsz2xKA6RjmHpOA5h/+ojJxEpI9NI2CrfDKOAgtJfoUJQg==", + "dev": true, + "requires": { + "cross-fetch": "^4.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7" + }, + "dependencies": { + "web3-utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.7.tgz", + "integrity": "sha512-sy8S6C2FIa5NNHc8DjND+Fx3S8KDAizuh5RbL1RX3h0PRbFgPfWzF5RfUns8gTt0mjJuOhs/IaDhrZfeTszG5A==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + } + } + } + }, + "web3-providers-ipc": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-4.0.7.tgz", + "integrity": "sha512-YbNqY4zUvIaK2MHr1lQFE53/8t/ejHtJchrWn9zVbFMGXlTsOAbNoIoZWROrg1v+hCBvT2c9z8xt7e/+uz5p1g==", + "dev": true, + "optional": true, + "requires": { + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7" + }, + "dependencies": { + "web3-utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.7.tgz", + "integrity": "sha512-sy8S6C2FIa5NNHc8DjND+Fx3S8KDAizuh5RbL1RX3h0PRbFgPfWzF5RfUns8gTt0mjJuOhs/IaDhrZfeTszG5A==", + "dev": true, + "optional": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + } + } + } + }, + "web3-providers-ws": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-4.0.7.tgz", + "integrity": "sha512-n4Dal9/rQWjS7d6LjyEPM2R458V8blRm0eLJupDEJOOIBhGYlxw5/4FthZZ/cqB7y/sLVi7K09DdYx2MeRtU5w==", + "dev": true, + "requires": { + "@types/ws": "8.5.3", + "isomorphic-ws": "^5.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "ws": "^8.8.1" + }, + "dependencies": { + "web3-utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.7.tgz", + "integrity": "sha512-sy8S6C2FIa5NNHc8DjND+Fx3S8KDAizuh5RbL1RX3h0PRbFgPfWzF5RfUns8gTt0mjJuOhs/IaDhrZfeTszG5A==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + } + } + } + }, + "web3-rpc-methods": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/web3-rpc-methods/-/web3-rpc-methods-1.1.3.tgz", + "integrity": "sha512-XB6SsCZZPdZUMPIRqDxJkZFKMu0/Y+yaExAt+Z7RqmuM7xF55fJ/Qb84LQho8zarvUoYziy4jnIfs+SXImxQUw==", + "dev": true, + "requires": { + "web3-core": "^4.3.0", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + }, + "dependencies": { + "web3-core": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-4.3.0.tgz", + "integrity": "sha512-//cy1W780nkMXd/9g2+GIa7KlHMuE+PJPhPD4NdwpUxvtQni6GkXSxtFnImZufyGVP+BpO5g7QneiSeu5ce+IQ==", + "dev": true, + "requires": { + "web3-errors": "^1.1.3", + "web3-eth-iban": "^4.0.7", + "web3-providers-http": "^4.1.0", + "web3-providers-ipc": "^4.0.7", + "web3-providers-ws": "^4.0.7", + "web3-types": "^1.3.0", + "web3-utils": "^4.0.7", + "web3-validator": "^2.0.3" + } + }, + "web3-utils": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.7.tgz", + "integrity": "sha512-sy8S6C2FIa5NNHc8DjND+Fx3S8KDAizuh5RbL1RX3h0PRbFgPfWzF5RfUns8gTt0mjJuOhs/IaDhrZfeTszG5A==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "web3-validator": "^2.0.3" + } + } + } + }, + "web3-types": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web3-types/-/web3-types-1.3.0.tgz", + "integrity": "sha512-ReRq6D0w6Mr6PkC8mtn6JwBgbVAobPFYNWFO994C7LzTNweYQegb0peri5KMpEHQm2iG2tQbiIyAAeseIohc2Q==", + "dev": true + }, + "web3-utils": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.0.5.tgz", + "integrity": "sha512-43xIM7rr3htYNzliVQLpWLQmEf4XX8IXgjvqLcEuC/xje14O5UQM4kamRCtz8v3JZN3X6QTfsV6Zgby67mVmCg==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "web3-errors": "^1.1.1", + "web3-types": "^1.1.1", + "web3-validator": "^2.0.1" + } + }, + "web3-validator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/web3-validator/-/web3-validator-2.0.3.tgz", + "integrity": "sha512-fJbAQh+9LSNWy+l5Ze6HABreml8fra98o5+vS073T35jUcLbRZ0IOjF/ZPJhJNbJDt+jP1vseZsc3z3uX9mxxQ==", + "dev": true, + "requires": { + "ethereum-cryptography": "^2.0.0", + "util": "^0.12.5", + "web3-errors": "^1.1.3", + "web3-types": "^1.3.0", + "zod": "^3.21.4" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "webpack": { + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + } + }, + "webpack-bundle-analyzer": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.0.tgz", + "integrity": "sha512-+bXGmO1LyiNx0i9enBu3H8mv42sj/BJWhZNFwjz92tVnBa9J3JMGo2an2IXlEleoDOPn/Hofl5hr/xCpObUDtw==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "chalk": "^4.1.0", + "commander": "^7.2.0", + "gzip-size": "^6.0.0", + "lodash": "^4.17.20", + "opener": "^1.5.2", + "sirv": "^1.0.7", + "ws": "^7.3.1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true + } + } + }, + "webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } + } + }, + "webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "wget-improved": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/wget-improved/-/wget-improved-3.4.0.tgz", + "integrity": "sha512-mHCdqImHntGzaauaQrfhkcHO0sAOp9Fd/9v5PXwrvHK+nggRWG9en5UH72/WitJFv3d3iFwJSAVMrRaCjW6dAA==", + "dev": true, + "requires": { + "minimist": "1.2.6", + "tunnel": "0.0.6" + }, + "dependencies": { + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + } + } + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true + }, + "which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + } + } + }, + "write-json-file": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-5.0.0.tgz", + "integrity": "sha512-ddSsCLa4aQ3kI21BthINo4q905/wfhvQ3JL3774AcRjBaiQmfn5v4rw77jQ7T6CmAit9VOQO+FsLyPkwxoB1fw==", + "dev": true, + "requires": { + "detect-indent": "^7.0.0", + "is-plain-obj": "^4.0.0", + "sort-keys": "^5.0.0", + "write-file-atomic": "^3.0.3" + }, + "dependencies": { + "is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + } + } + }, + "write-pkg": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-6.0.0.tgz", + "integrity": "sha512-lGAH18qfqlukADIiFz1khQQO+AfPcNKf+oJIktIADWISarSSG9MPoWmveT+GhTGh9nQLpw0iPZyucgbqDngHeQ==", + "dev": true, + "requires": { + "deepmerge-ts": "^5.1.0", + "read-pkg": "^8.0.0", + "sort-keys": "^5.0.0", + "type-fest": "^3.13.0", + "write-json-file": "^5.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dev": true, + "requires": { + "lru-cache": "^10.0.1" + } + }, + "json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true + }, + "lines-and-columns": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz", + "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==", + "dev": true + }, + "lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true + }, + "normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "dev": true, + "requires": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "parse-json": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.1.tgz", + "integrity": "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.21.4", + "error-ex": "^1.3.2", + "json-parse-even-better-errors": "^3.0.0", + "lines-and-columns": "^2.0.3", + "type-fest": "^3.8.0" + } + }, + "read-pkg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.1.0.tgz", + "integrity": "sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^6.0.0", + "parse-json": "^7.0.0", + "type-fest": "^4.2.0" + }, + "dependencies": { + "type-fest": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.6.0.tgz", + "integrity": "sha512-rLjWJzQFOq4xw7MgJrCZ6T1jIOvvYElXT12r+y0CC6u67hegDHaxcPqb2fZHOGlqxugGQPNB1EnTezjBetkwkw==", + "dev": true + } + } + }, + "type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true + } + } + }, + "ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "dev": true + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "dependencies": { + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, + "yargs-parser": { + "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 + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, + "zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "dev": true + } + } +} diff --git a/weaver/core/relay/Cargo.lock b/weaver/core/relay/Cargo.lock index 1f4d928cf1..4313593c0d 100644 --- a/weaver/core/relay/Cargo.lock +++ b/weaver/core/relay/Cargo.lock @@ -19,13 +19,14 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -89,7 +90,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.32", ] [[package]] @@ -100,7 +101,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.32", ] [[package]] @@ -500,7 +501,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.32", ] [[package]] @@ -586,9 +587,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" dependencies = [ "ahash", "allocator-api2", @@ -600,7 +601,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.1", + "hashbrown 0.14.2", ] [[package]] @@ -878,9 +879,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "matchit" @@ -1030,7 +1031,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.32", ] [[package]] @@ -1059,7 +1060,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.9", ] [[package]] @@ -1076,6 +1087,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets", +] + [[package]] name = "percent-encoding" version = "2.3.0" @@ -1109,7 +1133,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.32", ] [[package]] @@ -1218,6 +1242,28 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot 0.12.1", + "scheduled-thread-pool", +] + +[[package]] +name = "r2d2_sqlite" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99f31323d6161385f385046738df520e0e8694fa74852d35891fc0be08348ddc" +dependencies = [ + "r2d2", + "rusqlite", + "uuid", +] + [[package]] name = "rand" version = "0.8.5" @@ -1266,6 +1312,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "regex" version = "1.8.4" @@ -1295,7 +1350,11 @@ dependencies = [ "config", "dotenv", "futures", + "lazy_static", "listenfd", + "log", + "r2d2", + "r2d2_sqlite", "reqwest", "rusqlite", "serde 1.0.164", @@ -1454,6 +1513,15 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot 0.12.1", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1528,7 +1596,7 @@ checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.32", ] [[package]] @@ -1576,7 +1644,7 @@ dependencies = [ "fxhash", "libc", "log", - "parking_lot", + "parking_lot 0.11.2", ] [[package]] @@ -1620,9 +1688,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.22" +version = "2.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" dependencies = [ "proc-macro2", "quote", @@ -1700,7 +1768,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.32", ] [[package]] @@ -1857,7 +1925,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.32", ] [[package]] @@ -1930,6 +1998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" dependencies = [ "getrandom", + "rand", ] [[package]] @@ -1980,7 +2049,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.32", "wasm-bindgen-shared", ] @@ -2014,7 +2083,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.32", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2227,3 +2296,23 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "zerocopy" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd66a62464e3ffd4e37bd09950c2b9dd6c4f8767380fabba0d523f9a775bc85a" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "255c4596d41e6916ced49cfafea18727b24d67878fa180ddfd69b9df34fd1726" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index da64b2edb8..eaa35b7ca3 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -43,10 +43,10 @@ colored = {version="2.0.4"} rusqlite = "0.29.0" chrono = "0.4" dotenv = "0.15" +log = "0.4.20" +r2d2 = "0.8.10" +r2d2_sqlite = "0.22.0" +lazy_static = "1.4" [build-dependencies] -tonic-build = "0.8.4" - - - - +tonic-build = "0.8.4" \ No newline at end of file diff --git a/weaver/core/relay/docs/README.md b/weaver/core/relay/docs/README.md index 21e1d0b628..89c8ac49c3 100644 --- a/weaver/core/relay/docs/README.md +++ b/weaver/core/relay/docs/README.md @@ -17,6 +17,23 @@ sudo apt-get update sudo apt-get install libsqlite3-dev ``` +Use your favorite tool to create a SQLite database named 'gateway_log.db' and create the following table: +``` +CREATE TABLE log_entries ( + id INTEGER PRIMARY KEY, + debug_level TEXT, + timestamp TEXT, + request_id TEXT, + request TEXT, + step_id TEXT, + operation TEXT, + network_id TEXT, + gateway_id TEXT, + received TEXT, + details TEXT +); +``` + In a new terminal, run the following commands: ``` $ cd weaver/core/relay diff --git a/weaver/core/relay/src/main.rs b/weaver/core/relay/src/main.rs index 9ae14935fe..90267ba75b 100644 --- a/weaver/core/relay/src/main.rs +++ b/weaver/core/relay/src/main.rs @@ -24,14 +24,26 @@ use tokio::sync::RwLock; use tonic::transport::{Identity, Server, ServerTlsConfig}; use crate::services::satp_service::SatpService; +use lazy_static::lazy_static; +use crate::services::logger::DbLogger; mod db; mod error; mod relay_proto; mod services; +const SQLITE_DATABASE_FILE: &str = "gateway_log.db"; +lazy_static! { + static ref DB_LOGGER: DbLogger = DbLogger::new(SQLITE_DATABASE_FILE); +} + #[tokio::main] async fn main() -> Result<(), Box> { + log::set_logger(&*DB_LOGGER) + // TODO: database name and debug level should be configurable + .map(|()| log::set_max_level(log::LevelFilter::Debug)) + .expect("Logger should not have been set up yet"); + let mut settings = config::Config::default(); // Either get config path from environment variable or uses default. let config_file_name = env::var("RELAY_CONFIG").unwrap_or_else(|_| { diff --git a/weaver/core/relay/src/services/database.rs b/weaver/core/relay/src/services/database.rs deleted file mode 100644 index c0c59b6388..0000000000 --- a/weaver/core/relay/src/services/database.rs +++ /dev/null @@ -1,97 +0,0 @@ -use rusqlite::{params, Connection, Result}; -use serde::{Deserialize, Serialize}; -use std::error::Error; - -const SQLITE_DATABASE_FILE: &str = "gateway_log.db"; // Define a constant for the database filename - -// Define a Log struct that represents a log entry -pub struct Log { - pub timestamp: String, - pub request_id: String, - pub request: String, - pub step_id: String, - pub operation: Operation, - pub network_id: String, - pub gateway_id: String, - pub received: bool, - pub details: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum Operation { - Init, - Exec, - Done, - Failed, -} - -impl std::string::ToString for Operation { - fn to_string(&self) -> String { - match self { - Operation::Init => "Init".to_string(), - Operation::Exec => "Exec".to_string(), - Operation::Done => "Done".to_string(), - Operation::Failed => "Failed".to_string(), - } - } -} - -pub trait Database { - fn log(&self, log: &Log) -> Result<(), Box>; -} - -pub struct SqliteDatabase; - -impl SqliteDatabase { - fn create_logs_table(&self) -> Result<(), Box> { - // Open a connection to the SQLite database file - let conn = Connection::open(SQLITE_DATABASE_FILE)?; // Replace "log.db" with your database file - - // Create a table to store log entries if it doesn't exist - conn.execute( - "CREATE TABLE IF NOT EXISTS logs ( - id INTEGER PRIMARY KEY, - timestamp TEXT, - request_id TEXT, - request TEXT, - step_id TEXT, - operation TEXT, - network_id TEXT, - gateway_id TEXT, - received TEXT, - details TEXT - )", - params![], - )?; - - Ok(()) - } -} - -impl Database for SqliteDatabase { - fn log(&self, log: &Log) -> Result<(), Box> { - // Ensure the logs table exists - self.create_logs_table()?; - - // Open a connection to the SQLite database file - let conn = Connection::open(SQLITE_DATABASE_FILE)?; - - // Insert the log entry into the database - conn.execute( - "INSERT INTO logs (timestamp, request_id, request, step_id, operation, network_id, gateway_id, received, details) - VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)", - &[&log.timestamp, &log.request_id, &log.request, &log.step_id, &log.operation.to_string(), &log.network_id, &log.gateway_id, &(if log.received { "1".to_string() } else { "0".to_string() }), &log.details.as_ref().unwrap_or(&"".to_string())] - )?; - - Ok(()) - } -} - -pub struct PostgresDatabase; - -impl Database for PostgresDatabase { - fn log(&self, log: &Log) -> Result<(), Box> { - // TODO: Implement the logging logic for PostgreSQL - Ok(()) - } -} diff --git a/weaver/core/relay/src/services/logger.rs b/weaver/core/relay/src/services/logger.rs new file mode 100644 index 0000000000..1aae635923 --- /dev/null +++ b/weaver/core/relay/src/services/logger.rs @@ -0,0 +1,94 @@ +use log::{Log, Metadata, Record}; +use rusqlite::Connection; +use serde::{Serialize, Deserialize}; +use std::sync::Mutex; + +#[derive(Serialize, Deserialize)] +pub struct LogEntry { + pub request_id: String, + pub request: String, + pub step_id: String, + pub operation: Operation, + pub network_id: String, + pub gateway_id: String, + pub received: bool, + pub details: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Operation { + Init, + Exec, + Done, + Failed, +} + +impl std::fmt::Display for Operation { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Operation::Init => write!(f, "Init"), + Operation::Exec => write!(f, "Exec"), + Operation::Done => write!(f, "Done"), + Operation::Failed => write!(f, "Failed"), + } + } +} + +impl std::fmt::Display for LogEntry { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let json_str = serde_json::to_string(self).expect("Failed to serialize LogEntry to JSON"); + write!(f, "{}", json_str) + } +} + +pub(crate) struct DbLogger { + conn: Mutex, +} + +impl DbLogger { + pub fn new(database_path: &str) -> Self { + let conn = Connection::open(database_path).expect("Failed to open database"); + DbLogger { + conn: Mutex::new(conn), + } + } +} + +impl Log for DbLogger { + fn enabled(&self, _metadata: &Metadata) -> bool { + true + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + let conn = self.conn.lock().unwrap(); + + if let Ok(log_entry) = serde_json::from_str::(&record.args().to_string()) { + let mut details = "".to_string(); + if let Some(d) = log_entry.details.as_ref() { + details = d.to_string(); + } + + conn.execute( + "INSERT INTO log_entries (debug_level, timestamp, request_id, request, step_id, operation, gateway_id, received, details) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)", + &[ + &record.level().to_string(), // Log level + &format!("{}", chrono::Local::now()), // Timestamp + &log_entry.request_id, + &log_entry.request, + &log_entry.step_id, + &log_entry.operation.to_string(), + &log_entry.gateway_id, + &log_entry.received.to_string(), + &details, + ], + ) + .expect("Failed to insert log entry"); + + } + } + } + + fn flush(&self) {} +} + diff --git a/weaver/core/relay/src/services/mod.rs b/weaver/core/relay/src/services/mod.rs index f5f990722e..ddd7dc195d 100644 --- a/weaver/core/relay/src/services/mod.rs +++ b/weaver/core/relay/src/services/mod.rs @@ -11,4 +11,4 @@ pub mod helpers; pub mod satp_helper; pub mod types; pub mod constants; -pub mod database; +pub mod logger; \ No newline at end of file diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index cab94d6cdd..ae8face38d 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -1,6 +1,13 @@ +use crate::db::Database; +use crate::error::{self, Error}; +use crate::relay_proto::LocationSegment; +use crate::services::helpers::get_driver_client; +use crate::services::logger::Operation; +use chrono::Utc; use config::Config; +use dotenv::dotenv; use serde::de::DeserializeOwned; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use sled::IVec; use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use tonic::Response; @@ -18,47 +25,16 @@ use weaverpb::relay::satp::{ TransferProposalReceiptRequest, }; -use crate::db::Database; -use crate::error::{self, Error}; -use crate::relay_proto::LocationSegment; -use crate::services::helpers::get_driver_client; -use dotenv::dotenv; -use chrono::Utc; -use crate::services::database::Operation; -use super::database::{Log, PostgresDatabase, SqliteDatabase}; - use super::constants::{ SATP_DB_PATH, SATP_REMOTE_REQUESTS_DB_PATH, SATP_REMOTE_REQUESTS_STATES_DB_PATH, SATP_REQUESTS_DB_PATH, SATP_REQUESTS_STATES_DB_PATH, }; +use super::logger::LogEntry; use super::types::Driver; -fn choose_database() -> Box { - // Choose the appropriate database type (e.g., based on an environment variable) - let use_sqlite = std::env::var("USE_SQLITE").is_ok(); - - // Create a database instance - if use_sqlite { - Box::new(SqliteDatabase) - } else { - Box::new(PostgresDatabase) - } -} - -fn add_log( - database: &dyn super::database::Database, - log: Log, -) -> Result<(), Box> { - // Log the entry using the provided database - database.log(&log)?; - Ok(()) -} - -pub fn log_request(log: Log) { +pub fn log_request(log_entry: LogEntry) { dotenv().ok(); - - let database = choose_database(); - add_log(&*database, log).unwrap(); + log::debug!("{}", log_entry); } // Sends a request to the receiving gateway @@ -137,7 +113,7 @@ pub fn spawn_send_transfer_proposal_receipt_request( relay_host: String, relay_port: String, use_tls: bool, - tlsca_cert_path: String + tlsca_cert_path: String, ) { tokio::spawn(async move { let request_id = get_request_id_from_transfer_proposal_receipt( @@ -148,8 +124,7 @@ pub fn spawn_send_transfer_proposal_receipt_request( request_id ); - let log = Log { - timestamp: Utc::now().naive_utc().to_string(), + let log_entry = LogEntry { request_id: request_id.clone(), request: serde_json::to_string(&transfer_proposal_receipt_request.clone()).unwrap(), step_id: "1.2".to_string(), @@ -161,7 +136,7 @@ pub fn spawn_send_transfer_proposal_receipt_request( received: false, details: None, }; - log_request(log); + log::debug!("{}", log_entry); let result = call_transfer_proposal_receipt( relay_host, @@ -237,7 +212,7 @@ pub fn spawn_send_lock_assertion_broadcast_request( relay_host: String, relay_port: String, use_tls: bool, - tlsca_cert_path: String + tlsca_cert_path: String, ) { tokio::spawn(async move { let request_id = lock_assertion_request.session_id.to_string(); @@ -847,8 +822,7 @@ pub fn log_request_result( match ack::Status::from_i32(ack_response_into_inner.status) { Some(status) => match status { ack::Status::Ok => { - let log = Log { - timestamp: Utc::now().naive_utc().to_string(), + let log_entry = LogEntry { request_id: request_id.clone(), request: "".to_string(), step_id: "".to_string(), @@ -858,11 +832,10 @@ pub fn log_request_result( received: false, details: None, }; - log_request(log); + log::debug!("{}", log_entry); } ack::Status::Error => { - let log = Log { - timestamp: Utc::now().naive_utc().to_string(), + let log_entry = LogEntry { request_id: request_id.clone(), request: "".to_string(), step_id: "".to_string(), @@ -872,7 +845,7 @@ pub fn log_request_result( received: false, details: Some(ack_response_into_inner.message), }; - log_request(log); + log::debug!("{}", log_entry); } }, None => { @@ -881,8 +854,7 @@ pub fn log_request_result( } } Err(result_error) => { - let log = Log { - timestamp: Utc::now().naive_utc().to_string(), + let log_entry = LogEntry { request_id: request_id.clone(), request: "".to_string(), step_id: "".to_string(), @@ -892,7 +864,7 @@ pub fn log_request_result( received: false, details: Some(result_error.to_string()), }; - log_request(log); + log::debug!("{}", log_entry); } } } diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 2e81055572..16ecd43754 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -15,13 +15,13 @@ use weaverpb::relay::satp::{ // Internal modules use crate::error::Error; use crate::relay_proto::parse_address; -use crate::services::database::{Log, Operation}; use crate::services::helpers::{println_stage_heading, println_step_heading}; +use crate::services::logger::{LogEntry, Operation}; use crate::services::satp_helper::{ create_ack_error_message, create_assign_asset_request, create_create_asset_request, create_extinguish_request, create_perform_lock_request, - get_request_id_from_transfer_proposal_receipt, log_request_in_local_satp_db, - log_request_in_remote_satp_db, log_request, + get_request_id_from_transfer_proposal_receipt, log_request, log_request_in_local_satp_db, + log_request_in_remote_satp_db, }; use super::helpers::get_driver; @@ -78,18 +78,19 @@ impl Satp for SatpService { get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); let conf = self.config_lock.read().await; - let log = Log { - timestamp: Utc::now().naive_utc().to_string(), + let log_entry = LogEntry { request_id: request_id.clone(), request: serde_json::to_string(&transfer_proposal_claims_request.clone()).unwrap(), step_id: step_id.clone(), operation: Operation::Init, network_id: "todo_network_id".to_string(), - gateway_id: transfer_proposal_claims_request.clone().sender_gateway_network_id, + gateway_id: transfer_proposal_claims_request + .clone() + .sender_gateway_network_id, received: true, details: None, }; - log_request(log); + log::debug!("{}", log_entry); match process_transfer_proposal_claims_request( transfer_proposal_claims_request.clone(), @@ -101,35 +102,37 @@ impl Satp for SatpService { "Sending Ack of transfer proposal claims request back: {:?}\n", reply ); - let log = Log { - timestamp: Utc::now().naive_utc().to_string(), + let log_entry = LogEntry { request_id: request_id.clone(), request: serde_json::to_string(&transfer_proposal_claims_request).unwrap(), step_id: step_id.clone(), operation: Operation::Done, network_id: "todo_network_id".to_string(), - gateway_id: transfer_proposal_claims_request.clone().sender_gateway_network_id, + gateway_id: transfer_proposal_claims_request + .clone() + .sender_gateway_network_id, received: true, details: None, }; - log_request(log); + log::debug!("{}", log_entry); reply } Err(e) => { let error_message = "Transfer proposal claims failed.".to_string(); let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); - let log = Log { - timestamp: Utc::now().naive_utc().to_string(), + let log_entry = LogEntry { request_id: request_id.clone(), request: serde_json::to_string(&transfer_proposal_claims_request).unwrap(), step_id: step_id.clone(), operation: Operation::Failed, network_id: "todo_network_id".to_string(), - gateway_id: transfer_proposal_claims_request.clone().sender_gateway_network_id, + gateway_id: transfer_proposal_claims_request + .clone() + .sender_gateway_network_id, received: true, details: Some(error_message), }; - log_request(log); + log::debug!("{}", log_entry); reply } } @@ -702,18 +705,19 @@ pub fn process_transfer_proposal_claims_request( let transfer_proposal_receipt_request = create_transfer_proposal_receipt_request(transfer_proposal_claims_request.clone()); - let log = Log { - timestamp: Utc::now().naive_utc().to_string(), + let log_entry = LogEntry { request_id: request_id.clone(), request: serde_json::to_string(&transfer_proposal_claims_request.clone()).unwrap(), step_id: "1.1".to_string(), operation: Operation::Exec, network_id: "todo_network_id".to_string(), - gateway_id: transfer_proposal_claims_request.clone().sender_gateway_network_id, + gateway_id: transfer_proposal_claims_request + .clone() + .sender_gateway_network_id, received: true, details: None, }; - log_request(log); + log::debug!("{}", log_entry); match send_transfer_proposal_receipt_request(transfer_proposal_receipt_request, conf) { Ok(ack) => { @@ -1158,7 +1162,7 @@ fn send_transfer_proposal_receipt_request( relay_host, relay_port, use_tls, - tlsca_cert_path + tlsca_cert_path, ); let reply = Ack { @@ -1261,7 +1265,7 @@ fn send_lock_assertion_broadcast_request( relay_host, relay_port, use_tls, - tlsca_cert_path + tlsca_cert_path, ); let reply = Ack { status: ack::Status::Ok as i32, From 69fac1465728c02cd0d8cc208790876e2a14bb68 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 30 Oct 2023 17:56:18 +0000 Subject: [PATCH 46/59] feat: updated the .gitignore file --- weaver/core/relay/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/weaver/core/relay/.gitignore b/weaver/core/relay/.gitignore index bed3ac9952..d54cbf8c58 100644 --- a/weaver/core/relay/.gitignore +++ b/weaver/core/relay/.gitignore @@ -3,3 +3,4 @@ fingerprint.json protos-rs /db .env +*.db From 3c55604646144ed28f590d27321c82388b78fef9 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 31 Oct 2023 09:46:38 +0000 Subject: [PATCH 47/59] feat: added log entries to all requests --- weaver/core/relay/src/services/constants.rs | 5 - .../relay/src/services/network_service.rs | 63 +- weaver/core/relay/src/services/satp_helper.rs | 252 +----- .../core/relay/src/services/satp_service.rs | 800 ++++++++++++------ 4 files changed, 557 insertions(+), 563 deletions(-) diff --git a/weaver/core/relay/src/services/constants.rs b/weaver/core/relay/src/services/constants.rs index fc22e7bcc7..e69de29bb2 100644 --- a/weaver/core/relay/src/services/constants.rs +++ b/weaver/core/relay/src/services/constants.rs @@ -1,5 +0,0 @@ -pub static SATP_DB_PATH: &str = "db_satp_path"; -pub static SATP_REQUESTS_DB_PATH: &str = "/satp/requests"; -pub static SATP_REQUESTS_STATES_DB_PATH: &str = "/satp/requests_states"; -pub static SATP_REMOTE_REQUESTS_DB_PATH: &str = "/satp/remote_requests"; -pub static SATP_REMOTE_REQUESTS_STATES_DB_PATH: &str = "/satp/remote_requests_states"; \ No newline at end of file diff --git a/weaver/core/relay/src/services/network_service.rs b/weaver/core/relay/src/services/network_service.rs index 1d253ce9c5..98a3d1de79 100644 --- a/weaver/core/relay/src/services/network_service.rs +++ b/weaver/core/relay/src/services/network_service.rs @@ -28,8 +28,8 @@ use crate::services::helpers::{ }; use crate::services::satp_helper::{ create_transfer_proposal_claims_request, get_relay_from_transfer_proposal_claims, - get_relay_params, get_request_id_from_transfer_proposal_claims, log_request_in_local_satp_db, - log_request_state_in_local_satp_db, spawn_send_transfer_proposal_claims_request, + get_relay_params, get_request_id_from_transfer_proposal_claims, + spawn_send_transfer_proposal_claims_request, }; // External modules @@ -535,65 +535,11 @@ impl Network for NetworkService { create_transfer_proposal_claims_request(network_asset_transfer.clone()); let request_id = get_request_id_from_transfer_proposal_claims(transfer_proposal_claims_request.clone()); - // TODO refactor - let request_logged: Result, crate::error::Error> = - log_request_in_local_satp_db(&request_id, &network_asset_transfer, conf.clone()); - match request_logged { - Ok(_) => println!( - "Successfully stored NetworkAssetTransfer in local satp_db with request_id: {}", - request_id - ), - Err(e) => { - // Internal failure of sled. Send Error response - println!( - "Error storing NetworkAssetTransfer in local satp_db for request_id: {}", - request_id - ); - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: request_id, - message: format!( - "Error storing NetworkAssetTransfer in local satp_db {:?}", - e - ), - })); - println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); - return reply; - } - } - - // Initial request state stored in DB. - let target: RequestState = RequestState { - status: request_state::Status::PendingAck as i32, - request_id: request_id.clone(), - state: None, - }; - let request_state_logged: Result, crate::error::Error> = - log_request_state_in_local_satp_db(&request_id, &target, conf.clone()); - match request_state_logged { - Ok(_) => println!( - "Successfully stored RequestState in local satp_db with request_id: {}", - request_id - ), - Err(e) => { - // Internal failure of sled. Send Error response - println!( - "Error storing RequestState in local satp_db for request_id: {}", - request_id - ); - let reply = Ok(Response::new(Ack { - status: ack::Status::Error as i32, - request_id: request_id, - message: format!("Error storing RequestState in local satp_db {:?}", e), - })); - println!("Sending Ack back with an error to network of the asset transfer request: {:?}\n", reply); - return reply; - } - } + // TODO refactor / add log entry let parsed_address = parse_address(network_asset_transfer.address.to_string()); match parsed_address { - Ok(address) => { + Ok(_address) => { let (relay_host, relay_port) = get_relay_from_transfer_proposal_claims( transfer_proposal_claims_request.clone(), ); @@ -608,7 +554,6 @@ impl Network for NetworkService { relay_port, use_tls, tlsca_cert_path, - conf, ); // Send Ack back to network while request is happening in a thread let reply = Ack { diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index ae8face38d..283b44373d 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -1,18 +1,11 @@ -use crate::db::Database; -use crate::error::{self, Error}; +use crate::error::Error; use crate::relay_proto::LocationSegment; use crate::services::helpers::get_driver_client; use crate::services::logger::Operation; -use chrono::Utc; use config::Config; -use dotenv::dotenv; -use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; -use sled::IVec; use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use tonic::Response; use weaverpb::common::ack::{ack, Ack}; -use weaverpb::common::state::{request_state, RequestState}; use weaverpb::driver::driver::{ AssignAssetRequest, CreateAssetRequest, ExtinguishRequest, PerformLockRequest, }; @@ -24,19 +17,9 @@ use weaverpb::relay::satp::{ TransferCommenceRequest, TransferCompletedRequest, TransferProposalClaimsRequest, TransferProposalReceiptRequest, }; - -use super::constants::{ - SATP_DB_PATH, SATP_REMOTE_REQUESTS_DB_PATH, SATP_REMOTE_REQUESTS_STATES_DB_PATH, - SATP_REQUESTS_DB_PATH, SATP_REQUESTS_STATES_DB_PATH, -}; use super::logger::LogEntry; use super::types::Driver; -pub fn log_request(log_entry: LogEntry) { - dotenv().ok(); - log::debug!("{}", log_entry); -} - // Sends a request to the receiving gateway pub fn spawn_send_transfer_proposal_claims_request( transfer_proposal_claims_request: TransferProposalClaimsRequest, @@ -44,7 +27,6 @@ pub fn spawn_send_transfer_proposal_claims_request( relay_port: String, use_tls: bool, tlsca_cert_path: String, - conf: Config, ) { println!( "Sending transfer proposal claims request to receiver gateway: {:?}:{:?}", @@ -80,7 +62,6 @@ pub fn spawn_send_transfer_commence_request( relay_port: String, use_tls: bool, tlsca_cert_path: String, - conf: Config, ) { println!( "Sending transfer commence request to receiver gateway: {:?}:{:?}", @@ -159,7 +140,6 @@ pub fn spawn_send_ack_commence_request( relay_port: String, use_tls: bool, tlsca_cert_path: String, - conf: Config, ) { tokio::spawn(async move { let request_id = ack_commence_request.session_id.to_string(); @@ -247,7 +227,6 @@ pub fn spawn_send_lock_assertion_request( relay_port: String, use_tls: bool, tlsca_cert_path: String, - conf: Config, ) { tokio::spawn(async move { let request_id = lock_assertion_request.session_id.to_string(); @@ -275,7 +254,6 @@ pub fn spawn_send_commit_prepare_request( relay_port: String, use_tls: bool, tlsca_cert_path: String, - conf: Config, ) { println!( "Sending commit prepare request to receiver gateway: {:?}:{:?}", @@ -331,10 +309,8 @@ pub fn spawn_send_commit_ready_request( relay_port: String, use_tls: bool, tlsca_cert_path: String, - conf: Config, ) { tokio::spawn(async move { - let request_id = commit_ready_request.session_id.to_string(); let result = call_commit_ready( relay_host, relay_port, @@ -383,10 +359,8 @@ pub fn spawn_send_ack_final_receipt_request( relay_port: String, use_tls: bool, tlsca_cert_path: String, - conf: Config, ) { tokio::spawn(async move { - let request_id = ack_final_receipt_request.session_id.to_string(); let result = call_ack_final_receipt( relay_host, relay_port, @@ -409,7 +383,6 @@ pub fn spawn_send_ack_final_receipt_broadcast_request( relay_port: String, use_tls: bool, tlsca_cert_path: String, - conf: Config, ) { tokio::spawn(async move { let request_id = ack_final_receipt_request.session_id.to_string(); @@ -472,7 +445,6 @@ pub fn spawn_send_commit_final_assertion_request( relay_port: String, use_tls: bool, tlsca_cert_path: String, - conf: Config, ) { tokio::spawn(async move { let request_id = commit_final_assertion_request.session_id.to_string(); @@ -885,9 +857,8 @@ pub fn create_ack_error_message( } pub fn create_transfer_proposal_claims_request( - network_asset_transfer: NetworkAssetTransfer, + _network_asset_transfer: NetworkAssetTransfer, ) -> TransferProposalClaimsRequest { - let session_id = "to_be_calculated_session_id"; let transfer_proposal_claims_request = TransferProposalClaimsRequest { message_type: "message_type1".to_string(), client_identity_pubkey: "client_identity_pubkey1".to_string(), @@ -907,7 +878,7 @@ pub fn create_transfer_proposal_claims_request( } pub fn create_transfer_commence_request( - transfer_proposal_receipt_request: TransferProposalReceiptRequest, + _transfer_proposal_receipt_request: TransferProposalReceiptRequest, ) -> TransferCommenceRequest { let session_id = "to_be_calculated_session_id"; let transfer_commence_request = TransferCommenceRequest { @@ -925,7 +896,7 @@ pub fn create_transfer_commence_request( } pub fn create_transfer_proposal_receipt_request( - transfer_proposal_claims_request: TransferProposalClaimsRequest, + _transfer_proposal_claims_request: TransferProposalClaimsRequest, ) -> TransferProposalReceiptRequest { // TODO: remove hard coded values let transfer_proposal_receipt_request = TransferProposalReceiptRequest { @@ -947,7 +918,7 @@ pub fn create_transfer_proposal_receipt_request( } pub fn create_ack_commence_request( - transfer_commence_request: TransferCommenceRequest, + _transfer_commence_request: TransferCommenceRequest, ) -> AckCommenceRequest { // TODO: remove hard coded values let ack_commence_request = AckCommenceRequest { @@ -964,7 +935,7 @@ pub fn create_ack_commence_request( } pub fn create_lock_assertion_request( - send_asset_status_request: SendAssetStatusRequest, + _send_asset_status_request: SendAssetStatusRequest, ) -> LockAssertionRequest { // TODO: remove hard coded values let lock_assertion_request = LockAssertionRequest { @@ -984,7 +955,7 @@ pub fn create_lock_assertion_request( } pub fn create_lock_assertion_receipt_request( - lock_assertion_request: LockAssertionRequest, + _lock_assertion_request: LockAssertionRequest, ) -> LockAssertionReceiptRequest { // TODO: remove hard coded values let lock_assertion_receipt_request = LockAssertionReceiptRequest { @@ -1001,7 +972,7 @@ pub fn create_lock_assertion_receipt_request( } pub fn create_commit_prepare_request( - lock_assertion_receipt_request: LockAssertionReceiptRequest, + _lock_assertion_receipt_request: LockAssertionReceiptRequest, ) -> CommitPrepareRequest { // TODO: remove hard coded values let commit_prepare_request = CommitPrepareRequest { @@ -1013,7 +984,7 @@ pub fn create_commit_prepare_request( } pub fn create_commit_ready_request( - send_asset_status_request: SendAssetStatusRequest, + _send_asset_status_request: SendAssetStatusRequest, ) -> CommitReadyRequest { // TODO: remove hard coded values let commit_ready_request = CommitReadyRequest { @@ -1025,7 +996,7 @@ pub fn create_commit_ready_request( } pub fn create_commit_final_assertion_request( - send_asset_status_request: SendAssetStatusRequest, + _send_asset_status_request: SendAssetStatusRequest, ) -> CommitFinalAssertionRequest { // TODO: remove hard coded values let commit_final_assertion_request = CommitFinalAssertionRequest { @@ -1037,7 +1008,7 @@ pub fn create_commit_final_assertion_request( } pub fn create_ack_final_receipt_request( - send_asset_status_request: SendAssetStatusRequest, + _send_asset_status_request: SendAssetStatusRequest, ) -> AckFinalReceiptRequest { // TODO: remove hard coded values let ack_final_receipt_request = AckFinalReceiptRequest { @@ -1049,7 +1020,7 @@ pub fn create_ack_final_receipt_request( } pub fn create_transfer_completed_request( - ack_final_receipt_request: AckFinalReceiptRequest, + _ack_final_receipt_request: AckFinalReceiptRequest, ) -> TransferCompletedRequest { // TODO: remove hard coded values let transfer_completed_request = TransferCompletedRequest { @@ -1060,7 +1031,7 @@ pub fn create_transfer_completed_request( return transfer_completed_request; } -pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> PerformLockRequest { +pub fn create_perform_lock_request(_ack_commence_request: AckCommenceRequest) -> PerformLockRequest { // TODO: remove hard coded values let perform_lock_request = PerformLockRequest { session_id: "session_id1".to_string(), @@ -1069,7 +1040,7 @@ pub fn create_perform_lock_request(ack_commence_request: AckCommenceRequest) -> } pub fn create_create_asset_request( - commit_prepare_request: CommitPrepareRequest, + _commit_prepare_request: CommitPrepareRequest, ) -> CreateAssetRequest { // TODO: remove hard coded values let create_asset_request = CreateAssetRequest { @@ -1078,7 +1049,7 @@ pub fn create_create_asset_request( return create_asset_request; } -pub fn create_extinguish_request(commit_ready_request: CommitReadyRequest) -> ExtinguishRequest { +pub fn create_extinguish_request(_commit_ready_request: CommitReadyRequest) -> ExtinguishRequest { // TODO: remove hard coded values let extinguish_request = ExtinguishRequest { session_id: "session_id1".to_string(), @@ -1087,7 +1058,7 @@ pub fn create_extinguish_request(commit_ready_request: CommitReadyRequest) -> Ex } pub fn create_assign_asset_request( - commit_final_assertion_request: CommitFinalAssertionRequest, + _commit_final_assertion_request: CommitFinalAssertionRequest, ) -> AssignAssetRequest { // TODO: remove hard coded values let assign_asset_request = AssignAssetRequest { @@ -1096,242 +1067,81 @@ pub fn create_assign_asset_request( return assign_asset_request; } -pub fn generate_commit_final_assertion_request( - commit_ready_request: CommitReadyRequest, -) -> CommitFinalAssertionRequest { - // TODO Get the corresponding send_asset_status_request from db - // TODO: remove hard coded values - let commit_final_assertion_request = CommitFinalAssertionRequest { - message_type: "message_type1".to_string(), - session_id: "session_id1".to_string(), - transfer_context_id: "transfer_context_id1".to_string(), - }; - return commit_final_assertion_request; -} - -pub fn generate_commit_ready_request( - commit_prepare_request: CommitPrepareRequest, -) -> CommitReadyRequest { - // TODO Get the corresponding send_asset_status_request from db - // TODO: remove hard coded values - let commit_ready_request = CommitReadyRequest { - message_type: "message_type1".to_string(), - session_id: "session_id1".to_string(), - transfer_context_id: "transfer_context_id1".to_string(), - }; - return commit_ready_request; -} - -pub fn generate_ack_final_receipt_request( - commit_final_assertion_request: CommitFinalAssertionRequest, -) -> AckFinalReceiptRequest { - // TODO Get the corresponding send_asset_status_request from db - // TODO: remove hard coded values - let ack_final_receipt_request = AckFinalReceiptRequest { - message_type: "message_type1".to_string(), - session_id: "session_id1".to_string(), - transfer_context_id: "transfer_context_id1".to_string(), - }; - return ack_final_receipt_request; -} - -pub fn get_satp_requests_local_db(conf: Config) -> Database { - let db = Database { - db_path: format!( - "{}{}", - conf.get_str(SATP_DB_PATH).unwrap(), - SATP_REQUESTS_DB_PATH - ), - db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, - }; - return db; -} - -pub fn get_satp_requests_remote_db(conf: Config) -> Database { - let db = Database { - db_path: format!( - "{}{}", - conf.get_str(SATP_DB_PATH).unwrap(), - SATP_REMOTE_REQUESTS_DB_PATH - ), - db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, - }; - return db; -} - -pub fn get_satp_requests_states_local_db(conf: Config) -> Database { - let db = Database { - db_path: format!( - "{}{}", - conf.get_str(SATP_DB_PATH).unwrap(), - SATP_REQUESTS_STATES_DB_PATH - ), - db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, - }; - return db; -} - -pub fn get_satp_requests_states_remote_db(conf: Config) -> Database { - let db = Database { - db_path: format!( - "{}{}", - conf.get_str(SATP_DB_PATH).unwrap(), - SATP_REMOTE_REQUESTS_STATES_DB_PATH - ), - db_open_max_retries: conf.get_int("db_open_max_retries").unwrap_or(500) as u32, - db_open_retry_backoff_msec: conf.get_int("db_open_retry_backoff_msec").unwrap_or(10) as u32, - }; - return db; -} - -pub fn log_request_state_in_local_satp_db( - request_id: &String, - target: &RequestState, - conf: Config, -) -> Result, error::Error> { - let db = get_satp_requests_states_local_db(conf); - return db.set(&request_id, &target); -} - -pub fn log_request_in_local_satp_db( - request_id: &String, - value: T, - conf: Config, -) -> Result, error::Error> { - let db = get_satp_requests_local_db(conf); - return db.set(&request_id, &value); -} - -pub fn log_request_in_remote_satp_db( - request_id: &String, - value: T, - conf: Config, -) -> Result, error::Error> { - let db = get_satp_requests_remote_db(conf); - return db.set(&request_id, &value); -} - -pub fn get_request_from_remote_satp_db( - request_id: &String, - conf: Config, -) -> Result { - let db = get_satp_requests_remote_db(conf); - let query: Result = db - .get::(request_id.to_string()) - .map_err(|e| Error::GetQuery(format!("Failed to get query from db. Error: {:?}", e))); - return query; -} - -pub fn update_request_state_in_local_satp_db( - request_id: String, - new_status: request_state::Status, - state: Option, - conf: Config, -) { - let db = get_satp_requests_states_local_db(conf); - let target: RequestState = RequestState { - status: new_status as i32, - request_id: request_id.clone(), - state, - }; - db.set(&request_id, &target) - .expect("Failed to insert into DB"); - println!("Successfully written RequestState to database"); - println!("{:?}\n", db.get::(request_id).unwrap()) -} - pub fn get_relay_from_transfer_proposal_claims( - transfer_proposal_claims_request: TransferProposalClaimsRequest, + _transfer_proposal_claims_request: TransferProposalClaimsRequest, ) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } pub fn get_relay_from_transfer_proposal_receipt( - transfer_proposal_receipt_request: TransferProposalReceiptRequest, + _transfer_proposal_receipt_request: TransferProposalReceiptRequest, ) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } pub fn get_relay_from_transfer_commence( - transfer_commence_request: TransferCommenceRequest, + _transfer_commence_request: TransferCommenceRequest, ) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } -pub fn get_relay_from_ack_commence(ack_commence_request: AckCommenceRequest) -> (String, String) { +pub fn get_relay_from_ack_commence(_ack_commence_request: AckCommenceRequest) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } pub fn get_relay_from_lock_assertion( - lock_assertion_request: LockAssertionRequest, -) -> (String, String) { - // TODO - return ("localhost".to_string(), "9085".to_string()); -} - -pub fn get_relay_from_lock_assertion_receipt( - lock_assertion_receipt_request: LockAssertionReceiptRequest, + _lock_assertion_request: LockAssertionRequest, ) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } pub fn get_relay_from_commit_prepare( - commit_prepare_request: CommitPrepareRequest, + _commit_prepare_request: CommitPrepareRequest, ) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } -pub fn get_relay_from_commit_ready(commit_ready_request: CommitReadyRequest) -> (String, String) { +pub fn get_relay_from_commit_ready(_commit_ready_request: CommitReadyRequest) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } pub fn get_relay_from_commit_final_assertion( - commit_final_assertion_request: CommitFinalAssertionRequest, + _commit_final_assertion_request: CommitFinalAssertionRequest, ) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } pub fn get_relay_from_ack_final_receipt( - ack_final_receipt_request: AckFinalReceiptRequest, -) -> (String, String) { - // TODO - return ("localhost".to_string(), "9085".to_string()); -} - -pub fn get_relay_from_send_asset_status( - send_asset_status_request: SendAssetStatusRequest, + _ack_final_receipt_request: AckFinalReceiptRequest, ) -> (String, String) { // TODO return ("localhost".to_string(), "9085".to_string()); } -pub fn get_driver_address_from_perform_lock(perform_lock_request: PerformLockRequest) -> String { +pub fn get_driver_address_from_perform_lock(_perform_lock_request: PerformLockRequest) -> String { // TODO return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); } -pub fn get_driver_address_from_create_asset(create_asset_request: CreateAssetRequest) -> String { +pub fn get_driver_address_from_create_asset(_create_asset_request: CreateAssetRequest) -> String { // TODO return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); } -pub fn get_driver_address_from_extinguish(extinguish_request: ExtinguishRequest) -> String { +pub fn get_driver_address_from_extinguish(_extinguish_request: ExtinguishRequest) -> String { // TODO return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); } -pub fn get_driver_address_from_assign_asset(assign_asset_request: AssignAssetRequest) -> String { +pub fn get_driver_address_from_assign_asset(_assign_asset_request: AssignAssetRequest) -> String { // TODO return "localhost:9085/Dummy_Network/abc:abc:abc:abc".to_string(); } @@ -1383,14 +1193,14 @@ pub async fn create_satp_client( } pub fn get_request_id_from_transfer_proposal_claims( - request: TransferProposalClaimsRequest, + _request: TransferProposalClaimsRequest, ) -> String { // TODO return "hard_coded_transfer_proposal_claims_request_id".to_string(); } pub fn get_request_id_from_transfer_proposal_receipt( - request: TransferProposalReceiptRequest, + _request: TransferProposalReceiptRequest, ) -> String { // TODO return "hard_coded_transfer_proposal_receipt_request_id".to_string(); diff --git a/weaver/core/relay/src/services/satp_service.rs b/weaver/core/relay/src/services/satp_service.rs index 16ecd43754..61d28bab9a 100644 --- a/weaver/core/relay/src/services/satp_service.rs +++ b/weaver/core/relay/src/services/satp_service.rs @@ -1,4 +1,3 @@ -use chrono::Utc; // Internal generated modules use weaverpb::common::ack::{ack, Ack}; use weaverpb::driver::driver::{ @@ -20,8 +19,7 @@ use crate::services::logger::{LogEntry, Operation}; use crate::services::satp_helper::{ create_ack_error_message, create_assign_asset_request, create_create_asset_request, create_extinguish_request, create_perform_lock_request, - get_request_id_from_transfer_proposal_receipt, log_request, log_request_in_local_satp_db, - log_request_in_remote_satp_db, + get_request_id_from_transfer_proposal_receipt, }; use super::helpers::get_driver; @@ -30,13 +28,12 @@ use super::satp_helper::{ create_ack_commence_request, create_ack_final_receipt_request, create_commit_final_assertion_request, create_commit_prepare_request, create_commit_ready_request, create_lock_assertion_request, create_transfer_commence_request, - create_transfer_completed_request, create_transfer_proposal_receipt_request, - get_driver_address_from_assign_asset, get_driver_address_from_create_asset, - get_driver_address_from_extinguish, get_driver_address_from_perform_lock, - get_relay_from_ack_commence, get_relay_from_ack_final_receipt, - get_relay_from_commit_final_assertion, get_relay_from_commit_prepare, - get_relay_from_commit_ready, get_relay_from_lock_assertion, get_relay_from_transfer_commence, - get_relay_from_transfer_proposal_receipt, get_relay_params, + create_transfer_proposal_receipt_request, get_driver_address_from_assign_asset, + get_driver_address_from_create_asset, get_driver_address_from_extinguish, + get_driver_address_from_perform_lock, get_relay_from_ack_commence, + get_relay_from_ack_final_receipt, get_relay_from_commit_final_assertion, + get_relay_from_commit_prepare, get_relay_from_commit_ready, get_relay_from_lock_assertion, + get_relay_from_transfer_commence, get_relay_from_transfer_proposal_receipt, get_relay_params, get_request_id_from_transfer_proposal_claims, spawn_send_ack_commence_request, spawn_send_ack_final_receipt_broadcast_request, spawn_send_ack_final_receipt_request, spawn_send_assign_asset_request, spawn_send_commit_final_assertion_request, @@ -132,7 +129,7 @@ impl Satp for SatpService { received: true, details: Some(error_message), }; - log::debug!("{}", log_entry); + log::error!("{}", log_entry); reply } } @@ -142,7 +139,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { - println_step_heading("1.2".to_string()); + let step_id = "1.2".to_string(); + println_step_heading(step_id.clone()); println!( "Got an ack transfer proposal receipt request from {:?} - {:?}", request.remote_addr(), @@ -155,31 +153,22 @@ impl Satp for SatpService { ); let conf = self.config_lock.read().await; - // TODO refactor - let request_logged: Result, Error> = log_request_in_local_satp_db( - &request_id, - &transfer_proposal_receipt_request, - conf.clone(), - ); - match request_logged { - Ok(_) => { - println!( - "Successfully stored TransferProposalReceiptRequest in local satp_db with request_id: {}", - request_id - ) - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing TransferProposalReceiptRequest in local satp_db for request_id" - .to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_proposal_receipt_request.clone()).unwrap(), + step_id: step_id.clone(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: transfer_proposal_receipt_request + .clone() + .sender_gateway_network_id, + received: true, + details: None, + }; + log::debug!("{}", log_entry); match process_transfer_proposal_receipt_request( - transfer_proposal_receipt_request, + transfer_proposal_receipt_request.clone(), conf.clone(), ) { Ok(ack) => { @@ -188,11 +177,38 @@ impl Satp for SatpService { "Sending Ack of transfer proposal receipt request back: {:?}\n", reply ); + + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_proposal_receipt_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Done, + network_id: "todo_network_id".to_string(), + gateway_id: transfer_proposal_receipt_request + .clone() + .sender_gateway_network_id, + received: true, + details: None, + }; + log::debug!("{}", log_entry); reply } Err(e) => { let error_message = "Ack transfer proposal receipt failed.".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); + let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_proposal_receipt_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Failed, + network_id: "todo_network_id".to_string(), + gateway_id: transfer_proposal_receipt_request + .clone() + .sender_gateway_network_id, + received: true, + details: Some(error_message), + }; + log::error!("{}", log_entry); reply } } @@ -204,7 +220,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { - println_step_heading("1.3".to_string()); + let step_id = "1.3".to_string(); + println_step_heading(step_id.clone()); println!( "Got a TransferCommenceRequest from {:?} - {:?}", request.remote_addr(), @@ -215,32 +232,52 @@ impl Satp for SatpService { let request_id = transfer_commence_request.session_id.to_string(); let conf = self.config_lock.read().await; - match log_request_in_remote_satp_db(&request_id, &transfer_commence_request, conf.clone()) { - Ok(_) => { - println!("Successfully stored TransferCommenceRequest in remote satp_db with request_id: {}", request_id); - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing TransferCommenceRequest in remote satp_db for request_id" - .to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_commence_request.clone()).unwrap(), + step_id: step_id.clone(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); - match process_transfer_commence_request(transfer_commence_request, conf.clone()) { + match process_transfer_commence_request(transfer_commence_request.clone(), conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!( "Sending Ack of transfer commence request back: {:?}\n", reply ); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_commence_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Done, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); reply } Err(e) => { let error_message = "Transfer commence failed.".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); + let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_commence_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Failed, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: Some(error_message), + }; + log::error!("{}", log_entry); reply } } @@ -250,7 +287,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { - println_step_heading("1.4".to_string()); + let step_id = "1.4".to_string(); + println_step_heading(step_id.clone()); println!( "Got an ack commence request from {:?} - {:?}", request.remote_addr(), @@ -261,34 +299,49 @@ impl Satp for SatpService { let request_id = ack_commence_request.session_id.to_string(); let conf = self.config_lock.read().await; - // TODO refactor - let request_logged: Result, Error> = - log_request_in_local_satp_db(&request_id, &ack_commence_request, conf.clone()); - match request_logged { - Ok(_) => { - println!( - "Successfully stored AckCommenceRequest in local satp_db with request_id: {}", - request_id - ) - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing AckCommenceRequest in local satp_db for request_id".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&ack_commence_request.clone()).unwrap(), + step_id: step_id.clone(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); - match process_ack_commence_request(ack_commence_request, conf.clone()) { + match process_ack_commence_request(ack_commence_request.clone(), conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!("Sending Ack of ack commence request back: {:?}\n", reply); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&ack_commence_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Done, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); reply } Err(e) => { let error_message = "Ack commence failed.".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); + let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&ack_commence_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Failed, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: Some(error_message), + }; + log::error!("{}", log_entry); reply } } @@ -308,38 +361,40 @@ impl Satp for SatpService { let request_id = send_asset_status_request.session_id.to_string(); let conf = self.config_lock.read().await; - // TODO refactor - let request_logged: Result, Error> = - log_request_in_local_satp_db(&request_id, &send_asset_status_request, conf.clone()); - match request_logged { - Ok(_) => { - println!( - "Successfully stored SendAssetStatusRequest in local satp_db with request_id: {}", - request_id - ) - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing SendAssetStatusRequest in local satp_db for request_id" - .to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } - - match process_send_asset_status_request(send_asset_status_request, conf.clone()) { + match process_send_asset_status_request(send_asset_status_request.clone(), conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!( "Sending Ack of send asset status request back: {:?}\n", reply ); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&send_asset_status_request).unwrap(), + step_id: "todo_step_id".to_string(), + operation: Operation::Done, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); reply } Err(e) => { let error_message = "Send asset status failed.".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); + let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&send_asset_status_request).unwrap(), + step_id: "todo_step_id".to_string(), + operation: Operation::Failed, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: Some(error_message), + }; + log::error!("{}", log_entry); reply } } @@ -349,7 +404,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { - println_step_heading("2.2".to_string()); + let step_id = "2.2".to_string(); + println_step_heading(step_id.clone()); println!( "Got a LockAssertionRequest from {:?} - {:?}", request.remote_addr(), @@ -360,29 +416,49 @@ impl Satp for SatpService { let request_id = lock_assertion_request.session_id.to_string(); let conf = self.config_lock.read().await; - match log_request_in_remote_satp_db(&request_id, &lock_assertion_request, conf.clone()) { - Ok(_) => { - println!("Successfully stored LockAssertionRequest in remote satp_db with request_id: {}", request_id); - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing LockAssertionRequest in remote satp_db for request_id" - .to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&lock_assertion_request.clone()).unwrap(), + step_id: step_id.clone(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); - match process_lock_assertion_request(lock_assertion_request, conf.clone()) { + match process_lock_assertion_request(lock_assertion_request.clone(), conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!("Sending Ack of lock assertion request back: {:?}\n", reply); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&lock_assertion_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Done, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); reply } Err(e) => { let error_message = "Lock assertion failed.".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); + let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&lock_assertion_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Failed, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: Some(error_message), + }; + log::error!("{}", log_entry); reply } } @@ -392,7 +468,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { - println_step_heading("2.4".to_string()); + let step_id = "2.4".to_string(); + println_step_heading(step_id.clone()); println!( "Got an lock assertion receipt request from {:?} - {:?}", request.remote_addr(), @@ -403,41 +480,55 @@ impl Satp for SatpService { let request_id = lock_assertion_receipt_request.session_id.to_string(); let conf = self.config_lock.read().await; - // TODO refactor - let request_logged: Result, Error> = log_request_in_local_satp_db( - &request_id, - &lock_assertion_receipt_request, - conf.clone(), - ); - match request_logged { - Ok(_) => { - println!( - "Successfully stored LockAssertionReceiptRequest in local satp_db with request_id: {}", - request_id - ) - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing LockAssertionReceiptRequest in local satp_db for request_id" - .to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&lock_assertion_receipt_request.clone()).unwrap(), + step_id: step_id.clone(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); - match process_lock_assertion_receipt_request(lock_assertion_receipt_request, conf.clone()) { + match process_lock_assertion_receipt_request( + lock_assertion_receipt_request.clone(), + conf.clone(), + ) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!( "Sending Ack of lock assertion receipt request back: {:?}\n", reply ); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&lock_assertion_receipt_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Done, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); reply } Err(e) => { let error_message = "Lock assertion receipt failed.".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); + let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&lock_assertion_receipt_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Failed, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: Some(error_message), + }; + log::error!("{}", log_entry); reply } } @@ -447,7 +538,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { - println_step_heading("3.1".to_string()); + let step_id = "3.1".to_string(); + println_step_heading(step_id.clone()); println!( "Got commit prepare request from {:?} - {:?}", request.remote_addr(), @@ -458,35 +550,49 @@ impl Satp for SatpService { let request_id = commit_prepare_request.session_id.to_string(); let conf = self.config_lock.read().await; - // TODO refactor - let request_logged: Result, Error> = - log_request_in_local_satp_db(&request_id, &commit_prepare_request, conf.clone()); - match request_logged { - Ok(_) => { - println!( - "Successfully stored CommitPrepareRequest in local satp_db with request_id: {}", - request_id - ) - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing CommitPrepareRequest in local satp_db for request_id" - .to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&commit_prepare_request.clone()).unwrap(), + step_id: step_id.clone(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); - match process_commit_prepare_request(commit_prepare_request, conf.clone()) { + match process_commit_prepare_request(commit_prepare_request.clone(), conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!("Sending Ack of commit prepare request back: {:?}\n", reply); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&commit_prepare_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Done, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); reply } Err(e) => { let error_message = "Commit prepare failed.".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); + let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&commit_prepare_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Failed, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: Some(error_message), + }; + log::error!("{}", log_entry); reply } } @@ -496,7 +602,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { - println_step_heading("3.3".to_string()); + let step_id = "3.3".to_string(); + println_step_heading(step_id.clone()); println!( "Got commit ready request from {:?} - {:?}", request.remote_addr(), @@ -507,34 +614,49 @@ impl Satp for SatpService { let request_id = commit_ready_request.session_id.to_string(); let conf = self.config_lock.read().await; - // TODO refactor - let request_logged: Result, Error> = - log_request_in_local_satp_db(&request_id, &commit_ready_request, conf.clone()); - match request_logged { - Ok(_) => { - println!( - "Successfully stored CommitReadyRequest in local satp_db with request_id: {}", - request_id - ) - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing CommitReadyRequest in local satp_db for request_id".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&commit_ready_request.clone()).unwrap(), + step_id: step_id.clone(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); - match process_commit_ready_request(commit_ready_request, conf.clone()) { + match process_commit_ready_request(commit_ready_request.clone(), conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!("Sending Ack of commit ready request back: {:?}\n", reply); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&commit_ready_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Done, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); reply } Err(e) => { let error_message = "Commit ready failed.".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); + let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&commit_ready_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Failed, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: Some(error_message), + }; + log::error!("{}", log_entry); reply } } @@ -544,7 +666,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { - println_step_heading("3.5".to_string()); + let step_id = "3.5".to_string(); + println_step_heading(step_id.clone()); println!( "Got commit final assertion request from {:?} - {:?}", request.remote_addr(), @@ -555,41 +678,55 @@ impl Satp for SatpService { let request_id = commit_final_assertion_request.session_id.to_string(); let conf = self.config_lock.read().await; - // TODO refactor - let request_logged: Result, Error> = log_request_in_local_satp_db( - &request_id, - &commit_final_assertion_request, - conf.clone(), - ); - match request_logged { - Ok(_) => { - println!( - "Successfully stored CommitFinalAssertionRequest in local satp_db with request_id: {}", - request_id - ) - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing CommitFinalAssertionRequest in local satp_db for request_id" - .to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&commit_final_assertion_request.clone()).unwrap(), + step_id: step_id.clone(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); - match process_commit_final_assertion_request(commit_final_assertion_request, conf.clone()) { + match process_commit_final_assertion_request( + commit_final_assertion_request.clone(), + conf.clone(), + ) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!( "Sending Ack of commit final assertion request back: {:?}\n", reply ); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&commit_final_assertion_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Done, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); reply } Err(e) => { let error_message = "Commit final assertion failed.".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); + let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&commit_final_assertion_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Failed, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: Some(error_message), + }; + log::error!("{}", log_entry); reply } } @@ -599,7 +736,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { - println_step_heading("3.7".to_string()); + let step_id = "3.7".to_string(); + println_step_heading(step_id.clone()); println!( "Got commit final assertion request from {:?} - {:?}", request.remote_addr(), @@ -610,38 +748,52 @@ impl Satp for SatpService { let request_id = ack_final_receipt_request.session_id.to_string(); let conf = self.config_lock.read().await; - // TODO refactor - let request_logged: Result, Error> = - log_request_in_local_satp_db(&request_id, &ack_final_receipt_request, conf.clone()); - match request_logged { - Ok(_) => { - println!( - "Successfully stored AckFinalReceiptRequest in local satp_db with request_id: {}", - request_id - ) - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing AckFinalReceiptRequest in local satp_db for request_id" - .to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&ack_final_receipt_request.clone()).unwrap(), + step_id: step_id.clone(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); - match process_ack_final_receipt_request(ack_final_receipt_request, conf.clone()) { + match process_ack_final_receipt_request(ack_final_receipt_request.clone(), conf.clone()) { Ok(ack) => { let reply = Ok(Response::new(ack)); println!( "Sending Ack of ack final receipt request back: {:?}\n", reply ); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&ack_final_receipt_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Done, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); reply } Err(e) => { let error_message = "Ack final receipt failed.".to_string(); - let reply = create_ack_error_message(request_id, error_message, e); + let reply = create_ack_error_message(request_id.clone(), error_message.clone(), e); + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&ack_final_receipt_request).unwrap(), + step_id: step_id.clone(), + operation: Operation::Failed, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: Some(error_message), + }; + log::error!("{}", log_entry); reply } } @@ -651,7 +803,8 @@ impl Satp for SatpService { &self, request: Request, ) -> Result, Status> { - println_step_heading("3.9".to_string()); + let step_id = "3.9".to_string(); + println_step_heading(step_id.clone()); println!( "Got commit final assertion request from {:?} - {:?}", request.remote_addr(), @@ -660,27 +813,18 @@ impl Satp for SatpService { let transfer_completed_request = request.into_inner().clone(); let request_id = transfer_completed_request.session_id.to_string(); - let conf = self.config_lock.read().await; - // TODO refactor - let request_logged: Result, Error> = - log_request_in_local_satp_db(&request_id, &transfer_completed_request, conf.clone()); - match request_logged { - Ok(_) => { - println!( - "Successfully stored TransferCompletedRequest in local satp_db with request_id: {}", - request_id - ) - } - Err(e) => { - // Internal failure of sled. Send Error response - let error_message = - "Error storing TransferCompletedRequest in local satp_db for request_id" - .to_string(); - let reply = create_ack_error_message(request_id, error_message, e); - return reply; - } - } + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_completed_request.clone()).unwrap(), + step_id: step_id.clone(), + operation: Operation::Init, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); let reply = Ack { status: ack::Status::Ok as i32, @@ -757,7 +901,20 @@ pub fn process_transfer_proposal_receipt_request( println!("The transfer proposal receipt request is valid\n"); let transfer_commence_request = create_transfer_commence_request(transfer_proposal_receipt_request.clone()); - match send_transfer_commence_request(transfer_commence_request, conf) { + + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&transfer_commence_request.clone()).unwrap(), + step_id: "1.2".to_string(), + operation: Operation::Exec, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); + + match send_transfer_commence_request(transfer_commence_request.clone(), conf) { Ok(ack) => { println!("Ack transfer proposal receipt request."); let reply = Ok(ack); @@ -794,7 +951,20 @@ pub fn process_transfer_commence_request( if is_valid_request { println!("The transfer commence request is valid\n"); let ack_commence_request = create_ack_commence_request(transfer_commence_request.clone()); - match send_ack_commence_request(ack_commence_request, conf) { + + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&ack_commence_request.clone()).unwrap(), + step_id: "1.3".to_string(), + operation: Operation::Exec, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); + + match send_ack_commence_request(ack_commence_request.clone(), conf) { Ok(ack) => { println!("Ack transfer commence request."); let reply = Ok(ack); @@ -833,7 +1003,20 @@ pub fn process_ack_commence_request( println!("The ack commence request is valid\n"); let perform_lock_request: PerformLockRequest = create_perform_lock_request(ack_commence_request); - match send_perform_lock_request(perform_lock_request, conf) { + + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&perform_lock_request.clone()).unwrap(), + step_id: "1.4".to_string(), + operation: Operation::Exec, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); + + match send_perform_lock_request(perform_lock_request.clone(), conf) { Ok(ack) => { println!("Ack ack commence request."); let reply = Ok(ack); @@ -937,6 +1120,19 @@ pub fn process_lock_assertion_request( if is_valid_request { println!("The lock assertion request is valid\n"); + + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&lock_assertion_request.clone()).unwrap(), + step_id: "2.2".to_string(), + operation: Operation::Exec, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); + match send_lock_assertion_broadcast_request(lock_assertion_request, conf) { Ok(ack) => { println!("Ack lock assertion request."); @@ -975,6 +1171,19 @@ pub fn process_lock_assertion_receipt_request( println!("The lock assertion receipt request is valid\n"); let commit_prepare_request = create_commit_prepare_request(lock_assertion_receipt_request.clone()); + + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&commit_prepare_request.clone()).unwrap(), + step_id: "2.4".to_string(), + operation: Operation::Exec, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); + match send_commit_prepare_request(commit_prepare_request, conf) { Ok(ack) => { println!("Ack lock assertion receipt request."); @@ -1012,6 +1221,19 @@ pub fn process_commit_prepare_request( println!("The commit prepare request is valid\n"); let create_asset_request: CreateAssetRequest = create_create_asset_request(commit_prepare_request); + + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&create_asset_request.clone()).unwrap(), + step_id: "3.1".to_string(), + operation: Operation::Exec, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); + match send_create_asset_request(create_asset_request, conf) { Ok(ack) => { println!("Ack commit prepare request."); @@ -1048,6 +1270,19 @@ pub fn process_commit_ready_request( if is_valid_request { println!("The commit ready request is valid\n"); let extinguish_request: ExtinguishRequest = create_extinguish_request(commit_ready_request); + + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&extinguish_request.clone()).unwrap(), + step_id: "3.3".to_string(), + operation: Operation::Exec, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); + match send_extinguish_request(extinguish_request, conf) { Ok(ack) => { println!("Ack commit ready request."); @@ -1086,6 +1321,19 @@ pub fn process_commit_final_assertion_request( println!("The commit final assertion request is valid\n"); let assign_asset_request: AssignAssetRequest = create_assign_asset_request(commit_final_assertion_request); + + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&assign_asset_request.clone()).unwrap(), + step_id: "3.5".to_string(), + operation: Operation::Exec, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); + match send_assign_asset_request(assign_asset_request, conf) { Ok(ack) => { println!("Ack commit final assertion request."); @@ -1121,6 +1369,19 @@ pub fn process_ack_final_receipt_request( // TODO some processing if is_valid_request { println!("The ack final receipt request is valid\n"); + + let log_entry = LogEntry { + request_id: request_id.clone(), + request: serde_json::to_string(&ack_final_receipt_request.clone()).unwrap(), + step_id: "3.7".to_string(), + operation: Operation::Exec, + network_id: "todo_network_id".to_string(), + gateway_id: "todo_gateway_id".to_string(), + received: true, + details: None, + }; + log::debug!("{}", log_entry); + match send_ack_final_receipt_broadcast_request(ack_final_receipt_request, conf) { Ok(ack) => { println!("Ack ack final receipt request."); @@ -1189,7 +1450,6 @@ fn send_transfer_commence_request( relay_port, use_tls, tlsca_cert_path, - conf, ); let reply = Ack { status: ack::Status::Ok as i32, @@ -1214,7 +1474,6 @@ fn send_ack_commence_request( relay_port, use_tls, tlsca_cert_path, - conf, ); let reply = Ack { status: ack::Status::Ok as i32, @@ -1239,7 +1498,6 @@ fn send_lock_assertion_request( relay_port, use_tls, tlsca_cert_path, - conf, ); let reply = Ack { status: ack::Status::Ok as i32, @@ -1325,7 +1583,6 @@ fn send_commit_prepare_request( relay_port, use_tls, tlsca_cert_path, - conf, ); let reply = Ack { status: ack::Status::Ok as i32, @@ -1351,7 +1608,6 @@ fn send_commit_ready_request( relay_port, use_tls, tlsca_cert_path, - conf, ); let reply = Ack { @@ -1448,7 +1704,6 @@ fn send_commit_final_assertion_request( relay_port, use_tls, tlsca_cert_path, - conf, ); let reply = Ack { @@ -1476,7 +1731,6 @@ fn send_ack_final_receipt_request( relay_port, use_tls, tlsca_cert_path, - conf, ); let reply = Ack { @@ -1532,8 +1786,6 @@ fn send_ack_final_receipt_broadcast_request( get_relay_from_ack_final_receipt(ack_final_receipt_request.clone()); let (use_tls, tlsca_cert_path) = get_relay_params(relay_host.clone(), relay_port.clone(), conf.clone()); - let transfer_completed_request = - create_transfer_completed_request(ack_final_receipt_request.clone()); spawn_send_ack_final_receipt_broadcast_request( ack_final_receipt_request, @@ -1541,7 +1793,6 @@ fn send_ack_final_receipt_broadcast_request( relay_port, use_tls, tlsca_cert_path, - conf, ); let reply = Ack { @@ -1553,71 +1804,64 @@ fn send_ack_final_receipt_broadcast_request( } fn is_valid_transfer_proposal_claims_request( - transfer_proposal_claims_request: TransferProposalClaimsRequest, + _transfer_proposal_claims_request: TransferProposalClaimsRequest, ) -> bool { //TODO true } fn is_valid_transfer_proposal_receipt_request( - transfer_proposal_receipt_request: TransferProposalReceiptRequest, + _transfer_proposal_receipt_request: TransferProposalReceiptRequest, ) -> bool { //TODO true } -fn is_valid_transfer_commence_request(transfer_commence_request: TransferCommenceRequest) -> bool { +fn is_valid_transfer_commence_request(_transfer_commence_request: TransferCommenceRequest) -> bool { //TODO true } -fn is_valid_ack_commence_request(ack_commence_request: AckCommenceRequest) -> bool { +fn is_valid_ack_commence_request(_ack_commence_request: AckCommenceRequest) -> bool { //TODO true } -fn is_valid_lock_assertion_request(lock_assertion_request: LockAssertionRequest) -> bool { +fn is_valid_lock_assertion_request(_lock_assertion_request: LockAssertionRequest) -> bool { //TODO true } fn is_valid_lock_assertion_receipt_request( - lock_assertion_receipt_request: LockAssertionReceiptRequest, + _lock_assertion_receipt_request: LockAssertionReceiptRequest, ) -> bool { //TODO true } -fn is_valid_commit_prepare_request(commit_prepare_request: CommitPrepareRequest) -> bool { +fn is_valid_commit_prepare_request(_commit_prepare_request: CommitPrepareRequest) -> bool { //TODO true } -fn is_valid_commit_ready_request(commit_ready_request: CommitReadyRequest) -> bool { +fn is_valid_commit_ready_request(_commit_ready_request: CommitReadyRequest) -> bool { //TODO true } fn is_valid_commit_final_assertion_request( - commit_final_assertion_request: CommitFinalAssertionRequest, + _commit_final_assertion_request: CommitFinalAssertionRequest, ) -> bool { //TODO true } -fn is_valid_ack_final_receipt_request(ack_final_receipt_request: AckFinalReceiptRequest) -> bool { - //TODO - true -} - -fn is_valid_transfer_completed_request( - transfer_completed_request: TransferCompletedRequest, -) -> bool { +fn is_valid_ack_final_receipt_request(_ack_final_receipt_request: AckFinalReceiptRequest) -> bool { //TODO true } -fn is_valid_send_asset_status_request(send_asset_status_request: SendAssetStatusRequest) -> bool { +fn is_valid_send_asset_status_request(_send_asset_status_request: SendAssetStatusRequest) -> bool { //TODO true } From 1b7a268b7d9cfd2d5d616398c8b874624bf90550 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Thu, 2 Nov 2023 12:58:05 +0000 Subject: [PATCH 48/59] feat: removed the unnecessary --- weaver/core/relay/src/services/satp_helper.rs | 69 ------------------- 1 file changed, 69 deletions(-) diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 283b44373d..7f32abbc3f 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -51,7 +51,6 @@ pub fn spawn_send_transfer_proposal_claims_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - log_request_result(&request_id, result); }); } @@ -85,7 +84,6 @@ pub fn spawn_send_transfer_commence_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - log_request_result(&request_id, result); }); } @@ -130,7 +128,6 @@ pub fn spawn_send_transfer_proposal_receipt_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - log_request_result(&request_id, result); }); } @@ -158,7 +155,6 @@ pub fn spawn_send_ack_commence_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - log_request_result(&request_id, result); }); } @@ -217,7 +213,6 @@ pub fn spawn_send_lock_assertion_broadcast_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = lock_assertion_receipt_request.session_id.to_string(); - log_request_result(&request_id, result); }); } @@ -243,7 +238,6 @@ pub fn spawn_send_lock_assertion_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = lock_assertion_request.session_id.to_string(); - log_request_result(&request_id, result); }); } @@ -273,7 +267,6 @@ pub fn spawn_send_commit_prepare_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway - log_request_result(&request_id, result); }); } @@ -323,7 +316,6 @@ pub fn spawn_send_commit_ready_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = commit_ready_request.session_id.to_string(); - log_request_result(&request_id, result); }); } @@ -373,7 +365,6 @@ pub fn spawn_send_ack_final_receipt_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = ack_final_receipt_request.session_id.to_string(); - log_request_result(&request_id, result); }); } @@ -409,7 +400,6 @@ pub fn spawn_send_ack_final_receipt_broadcast_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = transfer_completed_request.session_id.to_string(); - log_request_result(&request_id, result); }); } @@ -464,7 +454,6 @@ pub fn spawn_send_commit_final_assertion_request( println!("Received Ack from sending gateway: {:?}\n", result); // Updates the request in the DB depending on the response status from the sending gateway let request_id = commit_final_assertion_request.session_id.to_string(); - log_request_result(&request_id, result); }); } @@ -783,64 +772,6 @@ pub async fn call_commit_final_assertion_receipt( Ok(response) } -pub fn log_request_result( - request_id: &String, - result: Result, Box>, -) { - match result { - Ok(ack_response) => { - let ack_response_into_inner = ack_response.into_inner().clone(); - // This match first checks if the status is valid. - match ack::Status::from_i32(ack_response_into_inner.status) { - Some(status) => match status { - ack::Status::Ok => { - let log_entry = LogEntry { - request_id: request_id.clone(), - request: "".to_string(), - step_id: "".to_string(), - operation: Operation::Done, - network_id: "".to_string(), - gateway_id: "".to_string(), - received: false, - details: None, - }; - log::debug!("{}", log_entry); - } - ack::Status::Error => { - let log_entry = LogEntry { - request_id: request_id.clone(), - request: "".to_string(), - step_id: "".to_string(), - operation: Operation::Failed, - network_id: "".to_string(), - gateway_id: "".to_string(), - received: false, - details: Some(ack_response_into_inner.message), - }; - log::debug!("{}", log_entry); - } - }, - None => { - // TODO - } - } - } - Err(result_error) => { - let log_entry = LogEntry { - request_id: request_id.clone(), - request: "".to_string(), - step_id: "".to_string(), - operation: Operation::Failed, - network_id: "".to_string(), - gateway_id: "".to_string(), - received: false, - details: Some(result_error.to_string()), - }; - log::debug!("{}", log_entry); - } - } -} - pub fn create_ack_error_message( request_id: String, error_message: String, From 9c308aa5dc911f72dfb37e44f01c9823794d89d6 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Thu, 2 Nov 2023 13:03:05 +0000 Subject: [PATCH 49/59] feat: removed unnecessary comments --- weaver/core/relay/src/services/satp_helper.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 7f32abbc3f..03d1421be8 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -50,7 +50,6 @@ pub fn spawn_send_transfer_proposal_claims_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway }); } @@ -83,7 +82,6 @@ pub fn spawn_send_transfer_commence_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway }); } @@ -127,7 +125,6 @@ pub fn spawn_send_transfer_proposal_receipt_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway }); } @@ -154,7 +151,6 @@ pub fn spawn_send_ack_commence_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway }); } @@ -211,8 +207,6 @@ pub fn spawn_send_lock_assertion_broadcast_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway - let request_id = lock_assertion_receipt_request.session_id.to_string(); }); } @@ -236,8 +230,6 @@ pub fn spawn_send_lock_assertion_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway - let request_id = lock_assertion_request.session_id.to_string(); }); } @@ -255,7 +247,6 @@ pub fn spawn_send_commit_prepare_request( ); // Spawning new thread to make the call_commit_prepare to receiver gateway tokio::spawn(async move { - let request_id = commit_prepare_request.session_id.to_string(); let result = call_commit_prepare( relay_host, relay_port, @@ -266,7 +257,6 @@ pub fn spawn_send_commit_prepare_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway }); } @@ -314,8 +304,6 @@ pub fn spawn_send_commit_ready_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway - let request_id = commit_ready_request.session_id.to_string(); }); } @@ -363,8 +351,6 @@ pub fn spawn_send_ack_final_receipt_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway - let request_id = ack_final_receipt_request.session_id.to_string(); }); } @@ -398,8 +384,6 @@ pub fn spawn_send_ack_final_receipt_broadcast_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway - let request_id = transfer_completed_request.session_id.to_string(); }); } @@ -452,8 +436,6 @@ pub fn spawn_send_commit_final_assertion_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); - // Updates the request in the DB depending on the response status from the sending gateway - let request_id = commit_final_assertion_request.session_id.to_string(); }); } From 42e216a6e72223ad4c31cf6c82e0d009e2aaa23f Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Fri, 3 Nov 2023 08:04:30 +0000 Subject: [PATCH 50/59] feat: added the missing methods in driver --- weaver/core/relay/driver/driver.rs | 44 +++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/weaver/core/relay/driver/driver.rs b/weaver/core/relay/driver/driver.rs index 661d8bd8ed..fe58492e57 100644 --- a/weaver/core/relay/driver/driver.rs +++ b/weaver/core/relay/driver/driver.rs @@ -12,7 +12,10 @@ use weaverpb::common::state::{meta, view_payload, Meta, View, ViewPayload}; use weaverpb::driver::driver::driver_communication_server::{ DriverCommunication, DriverCommunicationServer, }; -use weaverpb::driver::driver::{PerformLockRequest, WriteExternalStateMessage}; +use weaverpb::driver::driver::{ + AssignAssetRequest, CreateAssetRequest, ExtinguishRequest, PerformLockRequest, + WriteExternalStateMessage, +}; use weaverpb::relay::datatransfer::data_transfer_client::DataTransferClient; use weaverpb::relay::events::event_subscribe_client::EventSubscribeClient; @@ -311,6 +314,45 @@ impl DriverCommunication for DriverCommunicationService { }; return Ok(Response::new(reply)); } + + async fn create_asset( + &self, + _request: Request, + ) -> Result, Status> { + // TODO + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: "".to_string(), + message: "".to_string(), + }; + return Ok(Response::new(reply)); + } + + async fn extinguish( + &self, + _request: Request, + ) -> Result, Status> { + // TODO + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: "".to_string(), + message: "".to_string(), + }; + return Ok(Response::new(reply)); + } + + async fn assign_asset( + &self, + _request: Request, + ) -> Result, Status> { + // TODO + let reply = Ack { + status: ack::Status::Ok as i32, + request_id: "".to_string(), + message: "".to_string(), + }; + return Ok(Response::new(reply)); + } } pub fn get_relay_from_perform_lock(perform_lock_request: PerformLockRequest) -> String { From 7ab00eb4f83b3e34e8bd12ac0c5df299386017e6 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Sat, 4 Nov 2023 13:19:31 +0000 Subject: [PATCH 51/59] feat: remove the unnecessary log statements --- weaver/core/relay/src/services/satp_helper.rs | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/weaver/core/relay/src/services/satp_helper.rs b/weaver/core/relay/src/services/satp_helper.rs index 03d1421be8..283b44373d 100644 --- a/weaver/core/relay/src/services/satp_helper.rs +++ b/weaver/core/relay/src/services/satp_helper.rs @@ -50,6 +50,8 @@ pub fn spawn_send_transfer_proposal_claims_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result(&request_id, result); }); } @@ -82,6 +84,8 @@ pub fn spawn_send_transfer_commence_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result(&request_id, result); }); } @@ -125,6 +129,8 @@ pub fn spawn_send_transfer_proposal_receipt_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result(&request_id, result); }); } @@ -151,6 +157,8 @@ pub fn spawn_send_ack_commence_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result(&request_id, result); }); } @@ -207,6 +215,9 @@ pub fn spawn_send_lock_assertion_broadcast_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = lock_assertion_receipt_request.session_id.to_string(); + log_request_result(&request_id, result); }); } @@ -230,6 +241,9 @@ pub fn spawn_send_lock_assertion_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = lock_assertion_request.session_id.to_string(); + log_request_result(&request_id, result); }); } @@ -247,6 +261,7 @@ pub fn spawn_send_commit_prepare_request( ); // Spawning new thread to make the call_commit_prepare to receiver gateway tokio::spawn(async move { + let request_id = commit_prepare_request.session_id.to_string(); let result = call_commit_prepare( relay_host, relay_port, @@ -257,6 +272,8 @@ pub fn spawn_send_commit_prepare_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + log_request_result(&request_id, result); }); } @@ -304,6 +321,9 @@ pub fn spawn_send_commit_ready_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = commit_ready_request.session_id.to_string(); + log_request_result(&request_id, result); }); } @@ -351,6 +371,9 @@ pub fn spawn_send_ack_final_receipt_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = ack_final_receipt_request.session_id.to_string(); + log_request_result(&request_id, result); }); } @@ -384,6 +407,9 @@ pub fn spawn_send_ack_final_receipt_broadcast_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = transfer_completed_request.session_id.to_string(); + log_request_result(&request_id, result); }); } @@ -436,6 +462,9 @@ pub fn spawn_send_commit_final_assertion_request( .await; println!("Received Ack from sending gateway: {:?}\n", result); + // Updates the request in the DB depending on the response status from the sending gateway + let request_id = commit_final_assertion_request.session_id.to_string(); + log_request_result(&request_id, result); }); } @@ -754,6 +783,64 @@ pub async fn call_commit_final_assertion_receipt( Ok(response) } +pub fn log_request_result( + request_id: &String, + result: Result, Box>, +) { + match result { + Ok(ack_response) => { + let ack_response_into_inner = ack_response.into_inner().clone(); + // This match first checks if the status is valid. + match ack::Status::from_i32(ack_response_into_inner.status) { + Some(status) => match status { + ack::Status::Ok => { + let log_entry = LogEntry { + request_id: request_id.clone(), + request: "".to_string(), + step_id: "".to_string(), + operation: Operation::Done, + network_id: "".to_string(), + gateway_id: "".to_string(), + received: false, + details: None, + }; + log::debug!("{}", log_entry); + } + ack::Status::Error => { + let log_entry = LogEntry { + request_id: request_id.clone(), + request: "".to_string(), + step_id: "".to_string(), + operation: Operation::Failed, + network_id: "".to_string(), + gateway_id: "".to_string(), + received: false, + details: Some(ack_response_into_inner.message), + }; + log::debug!("{}", log_entry); + } + }, + None => { + // TODO + } + } + } + Err(result_error) => { + let log_entry = LogEntry { + request_id: request_id.clone(), + request: "".to_string(), + step_id: "".to_string(), + operation: Operation::Failed, + network_id: "".to_string(), + gateway_id: "".to_string(), + received: false, + details: Some(result_error.to_string()), + }; + log::debug!("{}", log_entry); + } + } +} + pub fn create_ack_error_message( request_id: String, error_message: String, From 77ced9ed4d4448b7527d88423c6b61795d7052f2 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Wed, 22 Nov 2023 09:35:39 +0000 Subject: [PATCH 52/59] feat: initial rfcs for satp --- weaver/rfcs/formats/assets/satp.md | 237 ++++++++++++++++++ .../rfcs/models/infrastructure/relay_satp.md | 91 +++++++ .../protocols/satp/asset-transfer/corda.md | 1 + .../protocols/satp/asset-transfer/fabric.md | 27 ++ .../protocols/satp/asset-transfer/generic.md | 59 +++++ 5 files changed, 415 insertions(+) create mode 100644 weaver/rfcs/formats/assets/satp.md create mode 100644 weaver/rfcs/models/infrastructure/relay_satp.md create mode 100644 weaver/rfcs/protocols/satp/asset-transfer/corda.md create mode 100644 weaver/rfcs/protocols/satp/asset-transfer/fabric.md create mode 100644 weaver/rfcs/protocols/satp/asset-transfer/generic.md diff --git a/weaver/rfcs/formats/assets/satp.md b/weaver/rfcs/formats/assets/satp.md new file mode 100644 index 0000000000..fd1266228b --- /dev/null +++ b/weaver/rfcs/formats/assets/satp.md @@ -0,0 +1,237 @@ + +# Secure Asset Transfer (SAT) + +- RFC: +- Authors: Zakwan Jaroucheh, Venkatraman Ramakrishna, Sandeep Nishad, Rafael Belchior +- Status: Proposed +- Since: + +## Summary +This document specifies the data formats used in the [secure asset transfer protocol (SATP)](../../protocols/satp/asset-transfer/generic.md). The structures defined in this document are generic and the operations on them are generic (see the protocol specification for details.) These structures are oblivious to the specifications and semantics of any digital asset maintained by any DLT application (e.g., any application chaincode in Fabric or any CorDapp in Corda). + +## Transfer Initiation Claims negotiations (Stage-1) + +The purpose of this stage is for the sender gateway (G1) and the receiver gateway (G2) to agree on the asset instance to be transferred from the origin network NW1 to the destination network NW2. In addition, the gateways must exchange validated information or artifacts regarding the originator and beneficiary of the asset transfer, and exchange gateway-specific and network-specific parameters. + +These artifacts are contained in the Transfer Initiation Claims set that is sent from gateway G1 to G2. The set of claims may be negotiated between GH1 and G2 in multi-round set of messages. The first message (Transfer Proposal Claims) maybe multi-round in the sense there is a negotiation of the claims between G1 and G2. G1 sends the signed Transfer Initialization Claim to G2: + +```protobuf +message TransferProposalClaimsRequest { + string message_type = 1; + string asset_asset_id = 2; + string asset_profile_id = 3; + string verified_originator_entity_id = 4; + string verified_beneficiary_entity_id = 5; + string originator_pubkey = 6; + string beneficiary_pubkey = 7; + string sender_gateway_network_id = 8; + string recipient_gateway_network_id = 9; + string client_identity_pubkey = 10; + string server_identity_pubkey = 11; + string sender_gateway_owner_id = 12; + string receiver_gateway_owner_id = 13; +} +``` + +G2 accepts by signing Receipt containing hash of the TransferProposalClaimsRequest: + +```protobuf +message TransferProposalReceiptRequest { + string message_type = 1; + string asset_asset_id = 2; + string asset_profile_id = 3; + string verified_originator_entity_id = 4; + string verified_beneficiary_entity_id = 5; + string originator_pubkey = 6; + string beneficiary_pubkey = 7; + string sender_gateway_network_id = 8; + string recipient_gateway_network_id = 9; + string client_identity_pubkey = 10; + string server_identity_pubkey = 11; + string sender_gateway_owner_id = 12; + string receiver_gateway_owner_id = 13; +} +``` + +G1 chooses and opens a new session (SESSION_ID): +```protobuf +message TransferCommenceRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_transfer_init_claims = 6; + string hash_prev_message = 7; + string client_transfer_number = 8; + string client_signature = 9; +} +``` + +G2 agree to proceed (using the SESSION_ID): +```protobuf +message AckCommenceRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_prev_message = 6; + string server_transfer_number = 7; + string server_signature = 8; +} +``` + + +## Asset Lock Assertion and Receipt (Stage 2) + +In this stage, gateway G1 must issue a signed assertion that the asset in origin network NW1 has been immobilized and under the control of G1. + +G1 lock/escrow asset (2.1): Gateway G1 proceeds to establish a lock or escrow the asset belonging to the originator. This prevents other local transactions in NW1 from changing the state of the asset until such time the lock by G1 is finalized or released. A time-lock or escrow may also be employed: + +```protobuf +message PerformLockRequest { + string session_id = 1; +} +``` + +Lock Assertion (2.2): Gateway G1 sends a digitally signed assertion regarding the locked (escrowed or immobilized) state on the asset in network NW1. The signature by G1 is performed using its entity public-key pair. This signature signifies that G1 (i.e. its owner/operator) is legally standing behind its statement regarding the locked/escrowed state on the asset. The mechanism to lock or immobilize the asset is outside the scope of SATP: + +```protobuf +message LockAssertionRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string lock_assertion_claim = 6; + string lock_assertion_claim_format = 7; + string lock_assertion_expiration = 8; + string hash_prev_message = 9; + string client_transfer_number = 10; + string client_signature = 11; +} +``` + +G2 Logs and Broadcasts lock-assertion information (2.3): Gateway G2 logs a copy of the signed lock-assertion message received in Step 2.4 to its local state data DB2. G2 may also broadcast the fasts of the lock-assertion to all members of network NW2. The mechanism to log and to broadcast is out of scope for SATP: + +```protobuf +message LockAssertionBroadcastRequest { +} +``` + +Lock-Assertion Receipt (2.4): If gateway G2 accepts the signed assertion from G1, then G2 responds with a digitally signed receipt message which includes a hash of the previous lock-assertion message. The signature by G2 is performed using its entity public-key pair. Otherwise, if G2 declines accepting the assertion then G2 can simply ignore the transfer and let the session time-out (i.e. transfer attempt has failed): + +```protobuf +message LockAssertionReceiptRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_prev_message = 6; + string server_transfer_number = 7; + string server_signature = 8; +} +``` + +## Commitment Preparation and Finalization (Stage 3) + +In Stage 3 the gateways G1 and G2 finalizes to the asset transfer by performing a commitment protocol (e.g. 2PC or 3PC) as a process (sub-protocol) embedded within the overall SATP asset transfer protocol. + +Commit-prepare (3.1): Gateway G1 indicates to G2 to prepare for the commitment of the transfer. This message must include a hash of the previous messages (message 2.5 and 2.6): + +```protobuf +message CommitPrepareRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} +``` + +Temporary asset mint (3.2): Gateway G2 creates (mints) an equivalent asset in NW2 assigned to itself as the owner. This step can be reversed (i.e. asset destroyed) in the case of the failure in the commitment steps because G2 is still the owner of the asset in NW2: + +```protobuf +message CreateAssetRequest { + string session_id = 1; +} +``` + +Commit-ready (3.3): Gateway G2 sends a commit-ready message to G1 indicating that it is ready to carry-out the last steps of the commitment subprotocol. Note that that the entire asset transfer session can be aborted before this step without affecting the asset state in the respective networks: + +```protobuf +message CommitReadyRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} +``` + +Asset burn (3.4): Gateway G1 extinguishes (burns) the asset in network NW1 which it has locked since Step 2.3: + +```protobuf +message ExtinguishRequest { + string session_id = 1; +} +``` + +Commit-final assertion (3.5): Gateway G1 indicates to G2 that G1 has performed the extinguishment of the asset in NW1. This message must be digitally signed by G1: + +```protobuf +message CommitFinalAssertionRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} +``` + +Asset-assignment (3.6): Gateway G2 assigns the minted asset (which it has been self-holding since Step 3.2) to the Beneficiary: + +```protobuf +message AssignAssetRequest { + string session_id = 1; +} +``` + +ACK-final receipt (3.7): Gateway G2 sends a signed assertion that it has assigned the asset to the intended Beneficiary: + +```protobuf +message AckFinalReceiptRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} +``` + +Receipt broadcast (3.8) Gateway G1 logs a copy of the signed receipt message to its local state data DB2. G1 may also broadcast the fasts of the signed receipt to all members of network NW1. The mechanism to log and to broadcast is out of scope for SATP: + +```protobuf +message AckFinalReceiptBroadcastRequest { +} +``` + +Transfer complete (3.9): Gateway G1 must explicitly close the asset transfer session with gateway G2. This allows both sides to close down the secure channel established earlier in Stage 1: + + +```protobuf +message TransferCompletedRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} +``` + + + + + + + + + + + diff --git a/weaver/rfcs/models/infrastructure/relay_satp.md b/weaver/rfcs/models/infrastructure/relay_satp.md new file mode 100644 index 0000000000..c5d32c3a84 --- /dev/null +++ b/weaver/rfcs/models/infrastructure/relay_satp.md @@ -0,0 +1,91 @@ + +# Relay Messages + +- RFC: +- Authors: Zakwan Jaroucheh, Venkatraman Ramakrishna, Sandeep Nishad, Rafael Belchior +- Status: Proposed +- Since: + +## Summary + +This document specifies the GRPC services whenever the gateway is involved. + +## SATP Service + +```protobuf +service SATP { + // Stage 1 endpoints + + // The sender gateway sends a TransferProposalClaims request to initiate an asset transfer. + // Depending on the proposal, multiple rounds of communication between the two gateways may happen. + rpc TransferProposalClaims(TransferProposalClaimsRequest) returns (common.ack.Ack) {}; + + // The sender gateway sends a TransferProposalClaims request to signal to the receiver gateway + // that the it is ready to start the transfer of the digital asset + rpc TransferProposalReceipt(TransferProposalReceiptRequest) returns (common.ack.Ack) {}; + + // The sender gateway sends a TransferCommence request to signal to the receiver gateway + // that the it is ready to start the transfer of the digital asset + rpc TransferCommence(TransferCommenceRequest) returns (common.ack.Ack) {}; + + // The receiver gateway sends a AckCommence request to the sender gateway to indicate agreement + // to proceed with the asset transfer + rpc AckCommence(AckCommenceRequest) returns (common.ack.Ack) {}; + + // Stage 2 endpoints + + rpc SendAssetStatus(SendAssetStatusRequest) returns (common.ack.Ack) {}; + + // The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway + // declaring that the asset in question has been locked or escrowed by the sender gateway in + // the origin network (e.g. to prevent double spending) + rpc LockAssertion(LockAssertionRequest) returns (common.ack.Ack) {}; + + // The receiver gateway sends a LockAssertionReceipt request to the sender gateway to indicate acceptance + // of the claim(s) delivered by the sender gateway in the previous message + rpc LockAssertionReceipt(LockAssertionReceiptRequest) returns (common.ack.Ack) {}; + + rpc CommitPrepare(CommitPrepareRequest) returns (common.ack.Ack) {}; + + rpc CommitReady(CommitReadyRequest) returns (common.ack.Ack) {}; + + rpc CommitFinalAssertion(CommitFinalAssertionRequest) returns (common.ack.Ack) {}; + + rpc AckFinalReceipt(AckFinalReceiptRequest) returns (common.ack.Ack) {}; + + rpc TransferCompleted(TransferCompletedRequest) returns (common.ack.Ack) {}; +} + +``` + +## Driver Service + +```protobuf +service DriverCommunication { + // As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver + // to lock a specific asset + rpc PerformLock(PerformLockRequest) returns (common.ack.Ack) {} + + // As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + // to create a specific asset + rpc CreateAsset(CreateAssetRequest) returns (common.ack.Ack) {} + + // As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + // to extinguish a specific asset + rpc Extinguish(ExtinguishRequest) returns (common.ack.Ack) {} + + // As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + // to assign a specific asset + rpc AssignAsset(AssignAssetRequest) returns (common.ack.Ack) {} +} +``` + +## Database + +A gateway should maintain a database to store remote queries and state of the local queries at different stages of the [asset transfer](../../protocols/satp/asset-transfer/generic.md) protocol. Before running the gateway, you need to ensure SQLite (the default database for logs) is installed by following the [database initiaization documentation](../../../../../weaver/core/relay/docs/README.md). + + diff --git a/weaver/rfcs/protocols/satp/asset-transfer/corda.md b/weaver/rfcs/protocols/satp/asset-transfer/corda.md new file mode 100644 index 0000000000..f87f5c14cb --- /dev/null +++ b/weaver/rfcs/protocols/satp/asset-transfer/corda.md @@ -0,0 +1 @@ +# TODO \ No newline at end of file diff --git a/weaver/rfcs/protocols/satp/asset-transfer/fabric.md b/weaver/rfcs/protocols/satp/asset-transfer/fabric.md new file mode 100644 index 0000000000..b9e5b6ad4d --- /dev/null +++ b/weaver/rfcs/protocols/satp/asset-transfer/fabric.md @@ -0,0 +1,27 @@ + +# Asset Transfer Protocol Units in Fabric Networks + +- RFC: +- Authors: Zakwan Jaroucheh, Venkatraman Ramakrishna, Sandeep Nishad, Rafael Belchior +- Status: Proposed +- Since: + +## Summary + +- This document specifies the Hyperledger Fabric implementation of modules, and application adaptation guidelines, for the secure asset transfer protocol. +- Within Weaver, the protocol units to operate on the asset being transferred will be implemented in the Fabric Asset Transfer Chaincode for a Fabric-based network. +- The protocol unit functions are implemented in a library package that can be imported in any chaincode. +- Within Weaver, the SDK will provide user agents (clients) the capability to trigger transfer operations on particular chaincodes maintaining particular digital assets. + +## Fabric Asset Transfer Chaincode + +The following functions should be implemented in a separate package within the Fabric Asset Transfer Chaincode (*Note*: we use Golang syntax here because this chaincode is implemented within Weaver in Golang): + +- `func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error)`: locks an asset +- `func (s *SmartContract) AssignAsset(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string, claimInfoSerializedProto64 string) (bool, error)`: changes the ownser of an asset +- `func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, assetType, id string) error` deletes an asset + diff --git a/weaver/rfcs/protocols/satp/asset-transfer/generic.md b/weaver/rfcs/protocols/satp/asset-transfer/generic.md new file mode 100644 index 0000000000..a99d79efbf --- /dev/null +++ b/weaver/rfcs/protocols/satp/asset-transfer/generic.md @@ -0,0 +1,59 @@ + +# Secure Asset Transfer Protocol + +- RFC: +- Authors: Zakwan Jaroucheh, Venkatraman Ramakrishna, Sandeep Nishad, Rafael Belchior +- Status: Proposed +- Since: + +## Summary + +Secure asset transfer protocol in Weaver allows transferring an asset from one network to another. It is implemented by the gateways in the respective +networks. The two gateways implement the protocol in a direct interaction (unmediated). A successful transfer results in the asset being extinguished +(burned) or marked on the origin network, and for the asset to be regenerated (minted) at the destination network. + + +## Protocol Overview + +The secure asset transfer protocol provides a coordination between the two gateways through the various message flows in the protocol that is communicated over a secure channel. The protocol implements a commitment mechanism between the two gateways to ensure that the relevant properties atomicity, consistency, isolation, and durability are achieved in the transfer. + +The mechanism to extinguish (burn) or regenerate (mint) an asset from/into a network by its gateway is dependent on the specific network and is outside the scope of the current architecture. + +In a nutshell, the protocol can be described intuitively as follows: +- **Stage 0**: The two applications utilized by the originator and beneficiary is assumed to interact as part of the asset transfer. In this stage, +the applications App1 and App2 may establish some shared transfer context information (e.g. Context-ID) at the application level that will be made available to their respective gateways G1 and G2. +- **Stage 1**: In this stage gateways G1 and G2 must exchange information (claims) regarding the asset to be transferred, the identity information of the +Originator and Beneficiary and other information regarding relevant actors (e.g. gateway owner/operator). +- **Stage 2**: Gateway G1 must provide gateway G2 with a signed assertion that the asset in NW1 has been immobilized and under the control on G1. +- **Stage 3**: Gateways G1 and G2 commit to the unidirectional asset transfer using a 3PC (3-phase commit) subprotocol. + +## Generic Asset Transfer Flow + +The asset transfer flow is illustrated in more detail in the following figure, and in the description further below. It shows the protocol followed by Alice and Bob, using transaction within the ledgers and cross-network data sharing queries across the ledgers: + + + +## Prerequisites: Smart Contract Developer Responsibilities + +The triggers for each step in the SATP flow must come from the distributed applications pledging and acquiring the asset in question. Because the transfer involves ledger updates, the smart contract portion of the application (e.g., chaincode in Hyperledger Fabric, CorDapp contract in Corda) that processes ledger data through consensus must implement and expose (through its transaction API) several functions. See the [Fabric](./fabric.md) and [Corda](./corda.md) specifications for detailed guidelines when developing applications on those platforms. (*Note*: the function names specified in these pages are suggestive; the developer may pick any suitable names.) + +The application smart contract or distributed application offering these functions must already have mechanisms to: +- Uniquely identify assets and fetch their specifications +- Unambiguously identify the owner(s) of an asset +- Perform lock (or freeze) an asset; i.e., prevent any operations (state or ownership changes) on an asset +- Determine whether an asset is currently in the locked state +- Create an asset and specify the network as the owner +- Assign an asset to an owner by transferring the ownership of the asset from the network to the new owner +- Extinguish an asset by deleting it from the corresponding network + +How the smart contract implements these functions is beyond the purview of Weaver. + +## DLT-Specific Designs + +Implementation of the protocol is DLT-specific. See the following for details on currently supported DLTs: +- [Hyperledger Fabric](./fabric.md) +- [R3 Corda](./corda.md) From b552f18d9f12488ed5f8d3644576b0dbc2777674 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 27 Nov 2023 16:57:29 +0000 Subject: [PATCH 53/59] initial satp github action script --- .../test_weaver-fabric-fabric-satp.yaml | 275 +++----- .../drivers/fabric-driver/.env.satp.template | 25 + weaver/core/relay/Cargo.lock | 616 ++++++++---------- weaver/core/relay/Cargo.toml | 1 + weaver/core/relay/docs/README.md | 2 +- weaver/core/relay/src/main.rs | 4 +- weaver/samples/fabric/satpsimpleasset/go.mod | 2 +- weaver/samples/fabric/satpsimpleasset/go.sum | 8 - 8 files changed, 399 insertions(+), 534 deletions(-) create mode 100644 weaver/core/drivers/fabric-driver/.env.satp.template diff --git a/.github/workflows/test_weaver-fabric-fabric-satp.yaml b/.github/workflows/test_weaver-fabric-fabric-satp.yaml index 8ca1a23b13..5a2c777fae 100644 --- a/.github/workflows/test_weaver-fabric-fabric-satp.yaml +++ b/.github/workflows/test_weaver-fabric-fabric-satp.yaml @@ -4,7 +4,7 @@ # This is a basic workflow to help you get started with Actions -name: Test Asset Transfer +name: Secure Test Asset Transfer # Controls when the workflow will run on: @@ -23,7 +23,7 @@ concurrency: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: - fabric-fabric-asset-transfer-local: + fabric-fabric-satp-local: # if: ${{ false }} # The type of runner that the job will run on runs-on: ubuntu-latest @@ -76,6 +76,11 @@ jobs: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + # FABRIC NETWORK + - name: Start Fabric Network + run: make start-interop-local CHAINCODE_NAME=satpsimpleasset + working-directory: weaver/tests/network-setups/fabric/dev + # PROTOS - name: Build GO Protos run: | @@ -90,9 +95,9 @@ jobs: make build working-directory: weaver/common/protos-js - - name: Build Java Protos - run: make build - working-directory: weaver/common/protos-java-kt + # - name: Build Java Protos + # run: make build + # working-directory: weaver/common/protos-java-kt # Build Dependencies - name: Build Fabric Interop SDK @@ -111,79 +116,63 @@ jobs: run: make build-local working-directory: weaver/core/drivers/fabric-driver - - name: Build IIN Agent - run: make build-local - working-directory: weaver/core/identity-management/iin-agent - - # FABRIC NETWORK - - - name: Start Fabric Network - run: make start-interop-local CHAINCODE_NAME=simpleassettransfer - working-directory: weaver/tests/network-setups/fabric/dev - - # RELAY - - name: Start Relay for network1 - run: RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server &> relay-n1.out & - working-directory: weaver/core/relay + # - name: Build IIN Agent + # run: make build-local + # working-directory: weaver/core/identity-management/iin-agent - - name: Start Relay for network2 - run: RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server &> relay-n2.out & + # GATEWAY + - name: Start Relay for network1 and network2 + run: RELAY_CONFIG=config/Dummy_Relay.toml cargo run --bin server &> gateway.out & working-directory: weaver/core/relay # FABRIC DRIVER - name: Setup Fabric Driver .env run: | - cp .env.template .env - CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json - sed -i "s#path_to_connection_profile#${CCP_PATH}#g" .env - working-directory: weaver/core/drivers/fabric-driver - - - name: Start Fabric Driver for network1 - run: npm run dev &> fdriver-n1.out & + cp .env.satp.template .env working-directory: weaver/core/drivers/fabric-driver - - name: Start Fabric Driver for network2 - run: CONNECTION_PROFILE=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev &> fdriver-n2.out & + - name: Start Fabric Driver for network1 and network2 + run: npm run dev &> fdriver.out & working-directory: weaver/core/drivers/fabric-driver # IIN AGENT - - name: Setup Fabric IIN Config - run: | - # FABRIC CONFIG - cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n1.json - CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json - sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n1.json - cat src/fabric-ledger/config-n1.json - cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n2.json - CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json - sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n2.json - cat src/fabric-ledger/config-n2.json - # DNS CONFIG - sed -i "s#iin-agent-Org1MSP-network1#localhost#g" docker-testnet/configs/dnsconfig.json - sed -i "s#iin-agent-Org1MSP-network2#localhost#g" docker-testnet/configs/dnsconfig.json - cat docker-testnet/configs/dnsconfig.json - working-directory: weaver/core/identity-management/iin-agent - - - name: Setup Fabric IIN Env - run: | - cp .env.template .env - sed -i "s##Org1MSP#g" .env - sed -i "s#^DLT_TYPE=.*#DLT_TYPE=fabric#g" .env - sed -i "s##interop#g" .env - sed -i "s#^DNS_CONFIG_PATH=#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig.json#g" .env - sed -i "s#^SECURITY_DOMAIN_CONFIG_PATH=#SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json#g" .env - sed -i "s#^CONFIG_PATH=#CONFIG_PATH=./src/fabric-ledger/config-n1.json#g" .env - sed -i "s#^AUTO_SYNC=#AUTO_SYNC=false#g" .env - cat .env - working-directory: weaver/core/identity-management/iin-agent - - - name: Start Fabric IIN Agent for network1 - run: npm run dev &> iinagent-n1.out & - working-directory: weaver/core/identity-management/iin-agent - - - name: Start Fabric IIN Agent for network2 - run: IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2.json npm run dev &> iinagent-n2.out & - working-directory: weaver/core/identity-management/iin-agent + # - name: Setup Fabric IIN Config + # run: | + # # FABRIC CONFIG + # cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n1.json + # CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json + # sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n1.json + # cat src/fabric-ledger/config-n1.json + # cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n2.json + # CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json + # sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n2.json + # cat src/fabric-ledger/config-n2.json + # # DNS CONFIG + # sed -i "s#iin-agent-Org1MSP-network1#localhost#g" docker-testnet/configs/dnsconfig.json + # sed -i "s#iin-agent-Org1MSP-network2#localhost#g" docker-testnet/configs/dnsconfig.json + # cat docker-testnet/configs/dnsconfig.json + # working-directory: weaver/core/identity-management/iin-agent + + # - name: Setup Fabric IIN Env + # run: | + # cp .env.template .env + # sed -i "s##Org1MSP#g" .env + # sed -i "s#^DLT_TYPE=.*#DLT_TYPE=fabric#g" .env + # sed -i "s##interop#g" .env + # sed -i "s#^DNS_CONFIG_PATH=#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig.json#g" .env + # sed -i "s#^SECURITY_DOMAIN_CONFIG_PATH=#SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json#g" .env + # sed -i "s#^CONFIG_PATH=#CONFIG_PATH=./src/fabric-ledger/config-n1.json#g" .env + # sed -i "s#^AUTO_SYNC=#AUTO_SYNC=false#g" .env + # cat .env + # working-directory: weaver/core/identity-management/iin-agent + + # - name: Start Fabric IIN Agent for network1 + # run: npm run dev &> iinagent-n1.out & + # working-directory: weaver/core/identity-management/iin-agent + + # - name: Start Fabric IIN Agent for network2 + # run: IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2.json npm run dev &> iinagent-n2.out & + # working-directory: weaver/core/identity-management/iin-agent # FABRIC CLI - name: Setup Fabric CLI ENV @@ -193,7 +182,7 @@ jobs: ./bin/fabric-cli env set-file ./.env ./bin/fabric-cli env set MEMBER_CREDENTIAL_FOLDER ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/src/data/credentials ./bin/fabric-cli env set CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/config.json - ./bin/fabric-cli env set DEFAULT_APPLICATION_CHAINCODE simpleassettransfer + ./bin/fabric-cli env set DEFAULT_APPLICATION_CHAINCODE satpsimpleasset ./bin/fabric-cli env set REMOTE_CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/remote-network-config.json ./bin/fabric-cli env set CHAINCODE_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/chaincode.json cat .env @@ -206,8 +195,8 @@ jobs: sed -i "s##${GITHUB_WORKSPACE}/weaver#g" config.json ###### Change line number in following commands if config is modified ##### ./bin/fabric-cli config set network2 aclPolicyPrincipalType ca - ./bin/fabric-cli config set network1 chaincode simpleassettransfer - ./bin/fabric-cli config set network2 chaincode simpleassettransfer + ./bin/fabric-cli config set network1 chaincode satpsimpleasset + ./bin/fabric-cli config set network2 chaincode satpsimpleasset cp chaincode.json.template chaincode.json cp remote-network-config.json.template remote-network-config.json working-directory: weaver/samples/fabric/fabric-cli @@ -219,67 +208,33 @@ jobs: ./bin/fabric-cli configure create all --local-network=network2 ./bin/fabric-cli configure network --local-network=network1 ./bin/fabric-cli configure network --local-network=network2 - ./scripts/initAssetsForTransfer.sh + ./scripts/initAsset.sh working-directory: weaver/samples/fabric/fabric-cli - - name: Fabric Sync Membership using IIN Agent - run: | - ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 - sleep 10 - tail -10 ../../../core/identity-management/iin-agent/iinagent-n1.out - ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 - sleep 10 - tail -10 ../../../core/identity-management/iin-agent/iinagent-n2.out - working-directory: weaver/samples/fabric/fabric-cli + # - name: Fabric Sync Membership using IIN Agent + # run: | + # ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 + # sleep 10 + # tail -10 ../../../core/identity-management/iin-agent/iinagent-n1.out + # ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 + # sleep 10 + # tail -10 ../../../core/identity-management/iin-agent/iinagent-n2.out + # working-directory: weaver/samples/fabric/fabric-cli + + # CLIENT + - name: Start the client to initiate the satp protocol + run: cargo run --bin satp_client "9085" "localhost:9085/Dummy_Network/abc:abc:abc:abc" &> client.out & + working-directory: weaver/core/relay # FABRIC CLI - name: Asset Transfer Fabric CLI Non-Fungible Tests run: | COUNT=0 - TOTAL=8 - - # FABRIC2 - FABRIC1 - ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=bond --ref=a03 --data-file=src/data/assetsForTransfer.json &> tmp.out - tail -n 1 tmp.out | grep "Asset pledged with ID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') - - # FABRIC1 - FABRIC2 - ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a03 &> tmp.out - tail -n 1 tmp.out | grep "Called Function ClaimRemoteAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network1 &> tmp.out - tail -n 2 tmp.out | grep "Error: the asset a03 does not exist" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network2 &> tmp.out - #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=20 --type=bond --ref=a04 --data-file=src/data/assetsForTransfer.json &> tmp.out - cat tmp.out - - CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') - sleep 20 - - ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a04 &> tmp.out - tail -n 1 tmp.out | grep "cannot claim asset with pledgeId $CID as the expiry time has elapsed" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a04 &> tmp.out - tail -n 1 tmp.out | grep "Called Function ReclaimAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out + TOTAL=1 - ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network1 &> tmp.out - #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network2 &> tmp.out - tail -n 2 tmp.out | grep "Error: the asset a04 does not exist" && COUNT=$(( COUNT + 1 )) && echo "PASS" + ./bin/fabric-cli chaincode query --user=bob mychannel satpsimpleasset ReadAsset '["bond01","a0demo"]' --local-network=network2 &> tmp.out + #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a0demo\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a0demo\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out # RESULT @@ -292,76 +247,10 @@ jobs: fi working-directory: weaver/samples/fabric/fabric-cli - # FABRIC CLI - - name: Asset Transfer Fabric CLI Fungible Tests - run: | - COUNT=0 - TOTAL=8 - - # FABRIC2 - FABRIC1 - ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=token --units=50 --owner=alice --data-file=src/data/tokensForTransfer.json &> tmp.out - tail -n 1 tmp.out | grep "Asset pledged with ID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') - - # FABRIC1 - FABRIC2 - ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token.fabric --pledge-id=$CID --param=token1:50 &> tmp.out - tail -n 1 tmp.out | grep "Called Function ClaimRemoteTokenAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer GetMyWallet '[]' --local-network=network1 &> tmp.out - tail -n 2 tmp.out | grep "Result from network query: token1=\"9950\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer GetMyWallet '[]' --local-network=network2 &> tmp.out - tail -n 2 tmp.out | grep "Result from network query: token1=\"50\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=20 --type=token --units=100 --owner=alice --data-file=src/data/tokensForTransfer.json &> tmp.out - cat tmp.out - - CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') - sleep 20 - - ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token.fabric --pledge-id=$CID --param=token1:100 &> tmp.out - tail -n 1 tmp.out | grep "cannot claim asset with pledgeId $CID as the expiry time has elapsed" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=token.fabric --pledge-id=$CID --param=token1:100 &> tmp.out - tail -n 1 tmp.out | grep "Called Function ReclaimTokenAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer GetMyWallet '[]' --local-network=network1 &> tmp.out - tail -n 2 tmp.out | grep "Result from network query: token1=\"9950\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer GetMyWallet '[]' --local-network=network2 &> tmp.out - tail -n 2 tmp.out | grep "Result from network query: token1=\"50\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # RESULT - echo "Passed $COUNT/$TOTAL Tests." - - if [ $COUNT == $TOTAL ]; then - exit 0 - else - exit 1 - fi - working-directory: weaver/samples/fabric/fabric-cli - - - name: DEBUG Logs - fabric n1 relay - if: failure() - run: cat weaver/core/relay/relay-n1.out - - - name: DEBUG Logs - fabric n2 relay - if: failure() - run: cat weaver/core/relay/relay-n2.out - - - name: DEBUG Logs - fabric n1 driver + - name: DEBUG Logs - fabric n1 and n2 gateway if: failure() - run: cat weaver/core/drivers/fabric-driver/fdriver-n1.out + run: cat weaver/core/relay/gateway.out - - name: DEBUG Logs - fabric n2 driver + - name: DEBUG Logs - fabric n1 and n2 driver if: failure() - run: cat weaver/core/drivers/fabric-driver/fdriver-n2.out + run: cat weaver/core/drivers/fabric-driver/fdriver.out \ No newline at end of file diff --git a/weaver/core/drivers/fabric-driver/.env.satp.template b/weaver/core/drivers/fabric-driver/.env.satp.template new file mode 100644 index 0000000000..bfaa6bcf17 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/.env.satp.template @@ -0,0 +1,25 @@ +CONNECTION_PROFILE=/home/zakwan/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json +RELAY_ENDPOINT=localhost:9085 +RELAY_TLS=false +RELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay +DRIVER_ENDPOINT=localhost:9090 +DRIVER_TLS=false +DRIVER_TLS_CERT_PATH=path_to_tls_cert_pem_for_driver +DRIVER_TLS_KEY_PATH=path_to_tls_key_pem_for_driver +NETWORK_NAME=network1 +DRIVER_CONFIG= +INTEROP_CHAINCODE=interop +MOCK=false +DB_PATH=driverdbs +#WALLET_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/src/wallet-network1 +WALLET_PATH=/home/zakwan/cacti/weaver/core/drivers/fabric-driver/wallet-network1 +DEBUG=true +LEVELDB_LOCKED_MAX_RETRIES= +LEVELDB_LOCKED_RETRY_BACKOFF_MSEC= +ENABLE_MONITOR=false +MONITOR_SYNC_PERIOD= +MEMBER_CREDENTIAL_FOLDER=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/src/data/credentials +CONFIG_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/config.json +DEFAULT_APPLICATION_CHAINCODE=simpleassettransfer +REMOTE_CONFIG_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/remote-network-config.json +CHAINCODE_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/chaincode.json diff --git a/weaver/core/relay/Cargo.lock b/weaver/core/relay/Cargo.lock index c360b209cd..e3e338c608 100644 --- a/weaver/core/relay/Cargo.lock +++ b/weaver/core/relay/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -31,9 +31,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arrayvec" @@ -90,18 +90,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -112,9 +112,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", @@ -131,7 +131,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustversion", - "serde 1.0.164", + "serde 1.0.193", "sync_wrapper", "tower", "tower-layer", @@ -157,9 +157,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -184,9 +184,9 @@ checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bincode" @@ -194,7 +194,7 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "serde 1.0.164", + "serde 1.0.193", ] [[package]] @@ -205,15 +205,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byteorder" @@ -232,7 +232,7 @@ name = "cacti_weaver_protos_rs" version = "2.0.0-alpha.1" dependencies = [ "prost", - "serde 1.0.164", + "serde 1.0.193", "tonic", ] @@ -260,7 +260,7 @@ dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", - "num-traits 0.2.15", + "num-traits 0.2.17", "wasm-bindgen", "windows-targets", ] @@ -273,7 +273,7 @@ checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ "is-terminal", "lazy_static", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -285,7 +285,7 @@ dependencies = [ "lazy_static", "nom", "rust-ini", - "serde 1.0.164", + "serde 1.0.193", "serde-hjson", "serde_json", "toml", @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", @@ -381,23 +381,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ - "cc", "libc", + "windows-sys", ] [[package]] @@ -447,9 +436,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -466,9 +455,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -481,9 +470,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -491,15 +480,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -508,38 +497,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -564,9 +553,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -575,15 +564,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -591,7 +580,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -606,9 +595,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "ahash", "allocator-api2", @@ -620,7 +609,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.2", + "hashbrown 0.14.3", ] [[package]] @@ -631,7 +620,13 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "home" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ @@ -640,9 +635,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -695,7 +690,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -729,16 +724,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] @@ -752,9 +747,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -771,30 +766,29 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.12" +name = "indexmap" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ - "cfg-if", + "equivalent", + "hashbrown 0.14.3", ] [[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", + "cfg-if", ] [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" @@ -803,8 +797,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.9", - "windows-sys 0.48.0", + "rustix", + "windows-sys", ] [[package]] @@ -824,9 +818,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -852,9 +846,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libsqlite3-sys" @@ -874,15 +868,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "listenfd" @@ -897,9 +885,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -940,22 +928,22 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -999,14 +987,14 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" dependencies = [ - "num-traits 0.2.16", + "num-traits 0.2.17", ] [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -1023,9 +1011,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] @@ -1038,11 +1026,11 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -1059,7 +1047,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1070,9 +1058,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" dependencies = [ "cc", "libc", @@ -1130,9 +1118,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" @@ -1141,27 +1129,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.2", + "indexmap 2.1.0", ] [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1200,9 +1188,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -1263,9 +1251,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.29" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1333,28 +1321,30 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] -name = "redox_syscall" -version = "0.4.1" +name = "regex" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ - "bitflags 1.3.2", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "regex" -version = "1.8.4" +name = "regex-automata" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" - +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -1363,9 +1353,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "relay" @@ -1378,6 +1368,7 @@ dependencies = [ "colored", "config", "dotenv", + "env_logger", "futures", "lazy_static", "listenfd", @@ -1386,7 +1377,7 @@ dependencies = [ "r2d2_sqlite", "reqwest", "rusqlite", - "serde 1.0.164", + "serde 1.0.193", "serde_json", "sled", "tokio", @@ -1397,11 +1388,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64 0.21.2", + "base64 0.21.5", "bytes", "encoding_rs", "futures-core", @@ -1419,7 +1410,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "serde 1.0.164", + "serde 1.0.193", "serde_json", "serde_urlencoded", "system-configuration", @@ -1442,19 +1433,33 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", - "untrusted", + "spin 0.5.2", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys", +] + [[package]] name = "rusqlite" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -1476,28 +1481,15 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" -dependencies = [ - "bitflags 1.3.2", - "errno", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.9" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.5", - "windows-sys 0.48.0", + "linux-raw-sys", + "windows-sys", ] [[package]] @@ -1507,18 +1499,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" dependencies = [ "log", - "ring", + "ring 0.16.20", "sct", "webpki", ] [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.2", + "base64 0.21.5", ] [[package]] @@ -1559,19 +1551,19 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.5", + "untrusted 0.9.0", ] [[package]] name = "security-framework" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -1582,9 +1574,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -1598,9 +1590,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] @@ -1619,24 +1611,24 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", - "serde 1.0.164", + "serde 1.0.193", ] [[package]] @@ -1648,7 +1640,7 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde 1.0.164", + "serde 1.0.193", ] [[package]] @@ -1678,15 +1670,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -1694,9 +1686,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys", @@ -1708,6 +1700,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1727,9 +1725,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -1765,16 +1763,24 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.6.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ - "autocfg", "cfg-if", "fastrand", - "redox_syscall 0.3.5", - "rustix 0.37.20", - "windows-sys 0.48.0", + "redox_syscall 0.4.1", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", ] [[package]] @@ -1794,20 +1800,19 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374442f06ee49c3a28a8fc9f01a2596fed7559c6b99b31279c3261778e77d84f" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", - "socket2 0.5.4", + "socket2 0.5.5", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1822,13 +1827,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1865,9 +1870,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -1883,7 +1888,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "serde 1.0.164", + "serde 1.0.193", ] [[package]] @@ -1967,11 +1972,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1979,20 +1983,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] @@ -2021,9 +2025,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2040,11 +2044,17 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -2053,9 +2063,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.4.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ "getrandom", "rand", @@ -2090,9 +2100,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2100,24 +2110,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -2127,9 +2137,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2137,28 +2147,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -2166,12 +2176,12 @@ dependencies = [ [[package]] name = "webpki" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ecc0cd7cac091bf682ec5efa18b1cff79d617b84181f38b3951dbe135f607f" +checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring", - "untrusted", + "ring 0.17.5", + "untrusted 0.9.0", ] [[package]] @@ -2212,27 +2222,18 @@ dependencies = [ ] [[package]] -name = "windows" -version = "0.48.0" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets", -] +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows-core" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] @@ -2246,18 +2247,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" - +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -2266,84 +2266,42 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - [[package]] name = "winreg" version = "0.50.0" @@ -2365,20 +2323,20 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.20" +version = "0.7.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd66a62464e3ffd4e37bd09950c2b9dd6c4f8767380fabba0d523f9a775bc85a" +checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.20" +version = "0.7.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255c4596d41e6916ced49cfafea18727b24d67878fa180ddfd69b9df34fd1726" +checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index eaa35b7ca3..dca4221d65 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -47,6 +47,7 @@ log = "0.4.20" r2d2 = "0.8.10" r2d2_sqlite = "0.22.0" lazy_static = "1.4" +env_logger = "0.10.0" [build-dependencies] tonic-build = "0.8.4" \ No newline at end of file diff --git a/weaver/core/relay/docs/README.md b/weaver/core/relay/docs/README.md index 89c8ac49c3..e516fbcbb5 100644 --- a/weaver/core/relay/docs/README.md +++ b/weaver/core/relay/docs/README.md @@ -102,7 +102,7 @@ The Fabric-cli could be used for creating testing assets. Ensure you have the co $ cd weaver/samples/fabric/fabric-cli $ cat config.json -{`` +{ "network1": { "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json", "relayEndpoint": "localhost:9080", diff --git a/weaver/core/relay/src/main.rs b/weaver/core/relay/src/main.rs index df89e22236..0b2caeebdd 100644 --- a/weaver/core/relay/src/main.rs +++ b/weaver/core/relay/src/main.rs @@ -61,8 +61,8 @@ async fn main() -> Result<(), Box> { // Set the RUST_LOG environment variable env::set_var("RUST_LOG", &log_level); - // Initialize the logger - env_logger::init(); + // // Initialize the logger + // env_logger::init(); settings .merge(config::File::with_name(&config_file_name)) diff --git a/weaver/samples/fabric/satpsimpleasset/go.mod b/weaver/samples/fabric/satpsimpleasset/go.mod index a7d64f87cf..eedb9f8ddb 100644 --- a/weaver/samples/fabric/satpsimpleasset/go.mod +++ b/weaver/samples/fabric/satpsimpleasset/go.mod @@ -6,7 +6,7 @@ require ( github.com/golang/protobuf v1.5.3 github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 - github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils v0.0.0-20210920170720-5d5bf2a54081 + github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils v0.0.0-20230907062207-cd6eb2f89fb4 github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a github.com/hyperledger/fabric-contract-api-go v1.2.1 github.com/hyperledger/fabric-protos-go v0.3.0 diff --git a/weaver/samples/fabric/satpsimpleasset/go.sum b/weaver/samples/fabric/satpsimpleasset/go.sum index 23646b5a4f..da4c985ffd 100644 --- a/weaver/samples/fabric/satpsimpleasset/go.sum +++ b/weaver/samples/fabric/satpsimpleasset/go.sum @@ -147,11 +147,3 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha-prerelease h1:MpVTzM8FvQ+2Qij/0DH0cGy2NoC1S5gD5c40HuEQlsI= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha-prerelease/go.mod h1:3DmkYfZoc+TtcAgF3kX6CmQDNKKKCHgbaoQuYu/3ayc= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha-prerelease h1:kks9cM6vS3raV6Ag6FTddFdy11LvUAc6oYHVRUU95ts= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha-prerelease/go.mod h1:jzOMrtkM1AwBUgfedRs7FkcZpl1g/eRe1wnQO9GEoio= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 h1:r7RknfMWs/riL4saBB31iWfRaP03AJuo19K2ettHP3E= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1/go.mod h1:3DmkYfZoc+TtcAgF3kX6CmQDNKKKCHgbaoQuYu/3ayc= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 h1:ssYji+cWvfnPYRBQyx7J/aBVTaVdHbb2gOQOLfVZRCw= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1/go.mod h1:zei2BRZv+Ln+3o5yr7K900LRpEDCiado8px0hoGuuco= From 55f0af863d9fe38cf2d60725dea0f69cc040b61f Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 28 Nov 2023 07:52:05 +0000 Subject: [PATCH 54/59] corrected the github actions --- .../test_weaver-fabric-fabric-satp.yaml | 84 ++++--------------- .../drivers/fabric-driver/.env.satp.template | 14 ++-- .../fabric-cli/config.satp.template.json | 18 ++++ .../accessControlTemplate_ca.json | 29 +++++++ .../accessControlTemplate_certificate.json | 29 +++++++ .../verificationPolicyTemplate.json | 33 ++++++++ 6 files changed, 130 insertions(+), 77 deletions(-) create mode 100644 weaver/samples/fabric/fabric-cli/config.satp.template.json create mode 100644 weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_ca.json create mode 100644 weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_certificate.json create mode 100644 weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/verificationPolicyTemplate.json diff --git a/.github/workflows/test_weaver-fabric-fabric-satp.yaml b/.github/workflows/test_weaver-fabric-fabric-satp.yaml index 5a2c777fae..a40ca903e5 100644 --- a/.github/workflows/test_weaver-fabric-fabric-satp.yaml +++ b/.github/workflows/test_weaver-fabric-fabric-satp.yaml @@ -2,8 +2,6 @@ # # SPDX-License-Identifier: CC-BY-4.0 -# This is a basic workflow to help you get started with Actions - name: Secure Test Asset Transfer # Controls when the workflow will run @@ -21,18 +19,22 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true -# A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: fabric-fabric-satp-local: # if: ${{ false }} # The type of runner that the job will run on runs-on: ubuntu-latest - # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v3.5.2 + - name: Set up Docker Compose + run: | + curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + sudo chmod +x /usr/local/bin/docker-compose + docker-compose --version + - name: Install Yarn run: npm install -g yarn @@ -81,24 +83,20 @@ jobs: run: make start-interop-local CHAINCODE_NAME=satpsimpleasset working-directory: weaver/tests/network-setups/fabric/dev - # PROTOS + # PROTOS GO - name: Build GO Protos run: | export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" make build working-directory: weaver/common/protos-go - # PROTOS + # PROTOS JS - name: Build JS Protos run: | export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" make build working-directory: weaver/common/protos-js - # - name: Build Java Protos - # run: make build - # working-directory: weaver/common/protos-java-kt - # Build Dependencies - name: Build Fabric Interop SDK run: make build-local @@ -116,10 +114,6 @@ jobs: run: make build-local working-directory: weaver/core/drivers/fabric-driver - # - name: Build IIN Agent - # run: make build-local - # working-directory: weaver/core/identity-management/iin-agent - # GATEWAY - name: Start Relay for network1 and network2 run: RELAY_CONFIG=config/Dummy_Relay.toml cargo run --bin server &> gateway.out & @@ -129,51 +123,13 @@ jobs: - name: Setup Fabric Driver .env run: | cp .env.satp.template .env + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" .env working-directory: weaver/core/drivers/fabric-driver - name: Start Fabric Driver for network1 and network2 run: npm run dev &> fdriver.out & working-directory: weaver/core/drivers/fabric-driver - # IIN AGENT - # - name: Setup Fabric IIN Config - # run: | - # # FABRIC CONFIG - # cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n1.json - # CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json - # sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n1.json - # cat src/fabric-ledger/config-n1.json - # cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n2.json - # CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json - # sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n2.json - # cat src/fabric-ledger/config-n2.json - # # DNS CONFIG - # sed -i "s#iin-agent-Org1MSP-network1#localhost#g" docker-testnet/configs/dnsconfig.json - # sed -i "s#iin-agent-Org1MSP-network2#localhost#g" docker-testnet/configs/dnsconfig.json - # cat docker-testnet/configs/dnsconfig.json - # working-directory: weaver/core/identity-management/iin-agent - - # - name: Setup Fabric IIN Env - # run: | - # cp .env.template .env - # sed -i "s##Org1MSP#g" .env - # sed -i "s#^DLT_TYPE=.*#DLT_TYPE=fabric#g" .env - # sed -i "s##interop#g" .env - # sed -i "s#^DNS_CONFIG_PATH=#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig.json#g" .env - # sed -i "s#^SECURITY_DOMAIN_CONFIG_PATH=#SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json#g" .env - # sed -i "s#^CONFIG_PATH=#CONFIG_PATH=./src/fabric-ledger/config-n1.json#g" .env - # sed -i "s#^AUTO_SYNC=#AUTO_SYNC=false#g" .env - # cat .env - # working-directory: weaver/core/identity-management/iin-agent - - # - name: Start Fabric IIN Agent for network1 - # run: npm run dev &> iinagent-n1.out & - # working-directory: weaver/core/identity-management/iin-agent - - # - name: Start Fabric IIN Agent for network2 - # run: IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2.json npm run dev &> iinagent-n2.out & - # working-directory: weaver/core/identity-management/iin-agent - # FABRIC CLI - name: Setup Fabric CLI ENV run: | @@ -191,7 +147,7 @@ jobs: - name: Setup Fabric CLI Config run: | echo ${GITHUB_WORKSPACE} - cp config.template.json config.json + cp config.satp.template.json config.json sed -i "s##${GITHUB_WORKSPACE}/weaver#g" config.json ###### Change line number in following commands if config is modified ##### ./bin/fabric-cli config set network2 aclPolicyPrincipalType ca @@ -201,7 +157,6 @@ jobs: cp remote-network-config.json.template remote-network-config.json working-directory: weaver/samples/fabric/fabric-cli - - name: Fabric CLI Init run: | ./bin/fabric-cli configure create all --local-network=network1 @@ -211,30 +166,19 @@ jobs: ./scripts/initAsset.sh working-directory: weaver/samples/fabric/fabric-cli - # - name: Fabric Sync Membership using IIN Agent - # run: | - # ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 - # sleep 10 - # tail -10 ../../../core/identity-management/iin-agent/iinagent-n1.out - # ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 - # sleep 10 - # tail -10 ../../../core/identity-management/iin-agent/iinagent-n2.out - # working-directory: weaver/samples/fabric/fabric-cli - # CLIENT - name: Start the client to initiate the satp protocol run: cargo run --bin satp_client "9085" "localhost:9085/Dummy_Network/abc:abc:abc:abc" &> client.out & working-directory: weaver/core/relay - # FABRIC CLI - - name: Asset Transfer Fabric CLI Non-Fungible Tests + # Test SATP + - name: Test SATP run: | COUNT=0 TOTAL=1 - ./bin/fabric-cli chaincode query --user=bob mychannel satpsimpleasset ReadAsset '["bond01","a0demo"]' --local-network=network2 &> tmp.out - #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a0demo\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a0demo\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + ./bin/fabric-cli chaincode query --user=bob mychannel satpsimpleasset ReadAsset '["bond01","a04"]' --local-network=network1 &> tmp.out + cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out # RESULT diff --git a/weaver/core/drivers/fabric-driver/.env.satp.template b/weaver/core/drivers/fabric-driver/.env.satp.template index bfaa6bcf17..1be61e7341 100644 --- a/weaver/core/drivers/fabric-driver/.env.satp.template +++ b/weaver/core/drivers/fabric-driver/.env.satp.template @@ -1,4 +1,4 @@ -CONNECTION_PROFILE=/home/zakwan/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json +CONNECTION_PROFILE=/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json RELAY_ENDPOINT=localhost:9085 RELAY_TLS=false RELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay @@ -11,15 +11,15 @@ DRIVER_CONFIG= INTEROP_CHAINCODE=interop MOCK=false DB_PATH=driverdbs -#WALLET_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/src/wallet-network1 -WALLET_PATH=/home/zakwan/cacti/weaver/core/drivers/fabric-driver/wallet-network1 +#WALLET_PATH=/samples/fabric/fabric-cli/src/wallet-network1 +WALLET_PATH=/core/drivers/fabric-driver/wallet-network1 DEBUG=true LEVELDB_LOCKED_MAX_RETRIES= LEVELDB_LOCKED_RETRY_BACKOFF_MSEC= ENABLE_MONITOR=false MONITOR_SYNC_PERIOD= -MEMBER_CREDENTIAL_FOLDER=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/src/data/credentials -CONFIG_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/config.json +MEMBER_CREDENTIAL_FOLDER=/samples/fabric/fabric-cli/src/data/credentials +CONFIG_PATH=/samples/fabric/fabric-cli/config.json DEFAULT_APPLICATION_CHAINCODE=simpleassettransfer -REMOTE_CONFIG_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/remote-network-config.json -CHAINCODE_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/chaincode.json +REMOTE_CONFIG_PATH=/samples/fabric/fabric-cli/remote-network-config.json +CHAINCODE_PATH=/samples/fabric/fabric-cli/chaincode.json diff --git a/weaver/samples/fabric/fabric-cli/config.satp.template.json b/weaver/samples/fabric/fabric-cli/config.satp.template.json new file mode 100644 index 0000000000..171ab04eb0 --- /dev/null +++ b/weaver/samples/fabric/fabric-cli/config.satp.template.json @@ -0,0 +1,18 @@ +{ + "network1": { + "connProfilePath": "/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json", + "relayEndpoint": "localhost:9080", + "mspId": "Org1MSP", + "channelName": "mychannel", + "chaincode": "satpsimpleasset", + "aclPolicyPrincipalType": "ca" + }, + "network2": { + "connProfilePath": "/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json", + "relayEndpoint": "localhost:9083", + "mspId": "Org1MSP", + "channelName": "mychannel", + "chaincode": "satpsimpleasset", + "aclPolicyPrincipalType": "certificate" + } +} diff --git a/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_ca.json b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_ca.json new file mode 100644 index 0000000000..9d80467610 --- /dev/null +++ b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_ca.json @@ -0,0 +1,29 @@ +{ + "securityDomain": "", + "rules": [ + { + "principal": "", + "principalType": "ca", + "resource": "mychannel:satpsimpleasset:GetHTLCHash:*", + "read": true + }, + { + "principal": "", + "principalType": "ca", + "resource": "mychannel:satpsimpleasset:GetHTLCHashByContractId:*", + "read": true + }, + { + "principal": "", + "principalType": "ca", + "resource": "mychannel:satpsimpleasset:GetHTLCHashPreImage:*", + "read": true + }, + { + "principal": "", + "principalType": "ca", + "resource": "mychannel:satpsimpleasset:GetHTLCHashPreImageByContractId:*", + "read": true + } + ] +} diff --git a/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_certificate.json b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_certificate.json new file mode 100644 index 0000000000..79a86da0f8 --- /dev/null +++ b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_certificate.json @@ -0,0 +1,29 @@ +{ + "securityDomain": "", + "rules": [ + { + "principal": "", + "principalType": "certificate", + "resource": "mychannel:satpsimpleasset:GetHTLCHash:*", + "read": true + }, + { + "principal": "", + "principalType": "certificate", + "resource": "mychannel:satpsimpleasset:GetHTLCHashByContractId:*", + "read": true + }, + { + "principal": "", + "principalType": "certificate", + "resource": "mychannel:satpsimpleasset:GetHTLCHashPreImage:*", + "read": true + }, + { + "principal": "", + "principalType": "certificate", + "resource": "mychannel:satpsimpleasset:GetHTLCHashPreImageByContractId:*", + "read": true + } + ] +} diff --git a/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/verificationPolicyTemplate.json b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/verificationPolicyTemplate.json new file mode 100644 index 0000000000..747b48bd31 --- /dev/null +++ b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/verificationPolicyTemplate.json @@ -0,0 +1,33 @@ +{ + "securityDomain": "", + "identifiers": [ + { + "pattern": "mychannel:satpsimpleasset:GetHTLCHash:*", + "policy": { + "type": "Signature", + "criteria": [] + } + }, + { + "pattern": "mychannel:satpsimpleasset:GetHTLCHashByContractId:*", + "policy": { + "type": "Signature", + "criteria": [] + } + }, + { + "pattern": "mychannel:satpsimpleasset:GetHTLCHashPreImage:*", + "policy": { + "type": "Signature", + "criteria": [] + } + }, + { + "pattern": "mychannel:satpsimpleasset:GetHTLCHashPreImageByContractId:*", + "policy": { + "type": "Signature", + "criteria": [] + } + } + ] +} From db7ff82d72e375f0621f513ba3e3c4cff769c04c Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 11 Dec 2023 08:54:39 +0000 Subject: [PATCH 55/59] Corrected the protoc version to be 3.17.3 and rebuild corrected the version of cacti_weaver_protos_rs and added the copyright statement removed the code copied from fabric-cli --- .../protos-go/common/access_control.pb.go | 2 +- weaver/common/protos-go/common/ack.pb.go | 2 +- .../common/protos-go/common/asset_locks.pb.go | 2 +- .../protos-go/common/asset_transfer.pb.go | 2 +- weaver/common/protos-go/common/events.pb.go | 2 +- .../protos-go/common/interop_payload.pb.go | 2 +- .../common/protos-go/common/membership.pb.go | 2 +- weaver/common/protos-go/common/proofs.pb.go | 2 +- weaver/common/protos-go/common/query.pb.go | 2 +- weaver/common/protos-go/common/state.pb.go | 2 +- .../common/verification_policy.pb.go | 2 +- weaver/common/protos-go/corda/view_data.pb.go | 2 +- weaver/common/protos-go/driver/driver.pb.go | 2 +- .../common/protos-go/driver/driver_grpc.pb.go | 2 +- .../common/protos-go/fabric/view_data.pb.go | 2 +- weaver/common/protos-go/identity/agent.pb.go | 2 +- .../protos-go/identity/agent_grpc.pb.go | 2 +- .../common/protos-go/networks/networks.pb.go | 2 +- .../protos-go/networks/networks_grpc.pb.go | 2 +- .../protos-rs/pkg/src/generated/common.ack.rs | 4 + .../pkg/src/generated/common.events.rs | 4 + .../pkg/src/generated/common.query.rs | 4 + .../pkg/src/generated/common.state.rs | 4 + .../pkg/src/generated/driver.driver.rs | 4 + .../pkg/src/generated/networks.networks.rs | 4 + .../pkg/src/generated/relay.asset_transfer.rs | 4 + .../pkg/src/generated/relay.datatransfer.rs | 4 + .../pkg/src/generated/relay.events.rs | 4 + .../protos-rs/pkg/src/generated/relay.satp.rs | 4 + .../server/helpers/fabric-functions.ts | 714 ---------------- .../fabric-driver/server/helpers/helpers.ts | 764 ------------------ .../interop-setup/configure-network.ts | 230 ------ .../fabric-driver/server/helpers/logger.ts | 29 - .../core/drivers/fabric-driver/server/satp.ts | 4 +- weaver/core/relay/Cargo.toml | 2 +- weaver/core/relay/docs/README.md | 13 +- 36 files changed, 65 insertions(+), 1769 deletions(-) delete mode 100644 weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts delete mode 100644 weaver/core/drivers/fabric-driver/server/helpers/helpers.ts delete mode 100644 weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts delete mode 100644 weaver/core/drivers/fabric-driver/server/helpers/logger.ts diff --git a/weaver/common/protos-go/common/access_control.pb.go b/weaver/common/protos-go/common/access_control.pb.go index 266a1c203d..ee04dbca20 100644 --- a/weaver/common/protos-go/common/access_control.pb.go +++ b/weaver/common/protos-go/common/access_control.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/access_control.proto package common diff --git a/weaver/common/protos-go/common/ack.pb.go b/weaver/common/protos-go/common/ack.pb.go index 0b97f2fa93..74d14ab7c6 100644 --- a/weaver/common/protos-go/common/ack.pb.go +++ b/weaver/common/protos-go/common/ack.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/ack.proto package common diff --git a/weaver/common/protos-go/common/asset_locks.pb.go b/weaver/common/protos-go/common/asset_locks.pb.go index d844467dc6..468d81a6da 100644 --- a/weaver/common/protos-go/common/asset_locks.pb.go +++ b/weaver/common/protos-go/common/asset_locks.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/asset_locks.proto package common diff --git a/weaver/common/protos-go/common/asset_transfer.pb.go b/weaver/common/protos-go/common/asset_transfer.pb.go index 1e930e39b0..3f8040a669 100644 --- a/weaver/common/protos-go/common/asset_transfer.pb.go +++ b/weaver/common/protos-go/common/asset_transfer.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/asset_transfer.proto package common diff --git a/weaver/common/protos-go/common/events.pb.go b/weaver/common/protos-go/common/events.pb.go index da4ced1927..4e2bbdd5e8 100644 --- a/weaver/common/protos-go/common/events.pb.go +++ b/weaver/common/protos-go/common/events.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/events.proto package common diff --git a/weaver/common/protos-go/common/interop_payload.pb.go b/weaver/common/protos-go/common/interop_payload.pb.go index 0a1d3c5492..c8593d7e64 100644 --- a/weaver/common/protos-go/common/interop_payload.pb.go +++ b/weaver/common/protos-go/common/interop_payload.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/interop_payload.proto package common diff --git a/weaver/common/protos-go/common/membership.pb.go b/weaver/common/protos-go/common/membership.pb.go index 124f30a1a2..71f48b9700 100644 --- a/weaver/common/protos-go/common/membership.pb.go +++ b/weaver/common/protos-go/common/membership.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/membership.proto package common diff --git a/weaver/common/protos-go/common/proofs.pb.go b/weaver/common/protos-go/common/proofs.pb.go index 5611cd3ee5..cf8964ed0d 100644 --- a/weaver/common/protos-go/common/proofs.pb.go +++ b/weaver/common/protos-go/common/proofs.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/proofs.proto package common diff --git a/weaver/common/protos-go/common/query.pb.go b/weaver/common/protos-go/common/query.pb.go index e66e708342..82753902a5 100644 --- a/weaver/common/protos-go/common/query.pb.go +++ b/weaver/common/protos-go/common/query.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/query.proto package common diff --git a/weaver/common/protos-go/common/state.pb.go b/weaver/common/protos-go/common/state.pb.go index 30d8c72c85..1a56cb19e1 100644 --- a/weaver/common/protos-go/common/state.pb.go +++ b/weaver/common/protos-go/common/state.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/state.proto package common diff --git a/weaver/common/protos-go/common/verification_policy.pb.go b/weaver/common/protos-go/common/verification_policy.pb.go index bbdac635f4..34012c8c03 100644 --- a/weaver/common/protos-go/common/verification_policy.pb.go +++ b/weaver/common/protos-go/common/verification_policy.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/verification_policy.proto package common diff --git a/weaver/common/protos-go/corda/view_data.pb.go b/weaver/common/protos-go/corda/view_data.pb.go index 720eca12ac..d334b774b2 100644 --- a/weaver/common/protos-go/corda/view_data.pb.go +++ b/weaver/common/protos-go/corda/view_data.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: corda/view_data.proto package corda diff --git a/weaver/common/protos-go/driver/driver.pb.go b/weaver/common/protos-go/driver/driver.pb.go index 5ed253b931..2bc348cc64 100644 --- a/weaver/common/protos-go/driver/driver.pb.go +++ b/weaver/common/protos-go/driver/driver.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: driver/driver.proto package driver diff --git a/weaver/common/protos-go/driver/driver_grpc.pb.go b/weaver/common/protos-go/driver/driver_grpc.pb.go index ce978ce6f6..d7564b73fa 100644 --- a/weaver/common/protos-go/driver/driver_grpc.pb.go +++ b/weaver/common/protos-go/driver/driver_grpc.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.12.4 +// - protoc v3.17.3 // source: driver/driver.proto package driver diff --git a/weaver/common/protos-go/fabric/view_data.pb.go b/weaver/common/protos-go/fabric/view_data.pb.go index d2320f7369..76a9d5243c 100644 --- a/weaver/common/protos-go/fabric/view_data.pb.go +++ b/weaver/common/protos-go/fabric/view_data.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: fabric/view_data.proto package fabric diff --git a/weaver/common/protos-go/identity/agent.pb.go b/weaver/common/protos-go/identity/agent.pb.go index 2423d1bdb2..242b1cf27d 100644 --- a/weaver/common/protos-go/identity/agent.pb.go +++ b/weaver/common/protos-go/identity/agent.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: identity/agent.proto package identity diff --git a/weaver/common/protos-go/identity/agent_grpc.pb.go b/weaver/common/protos-go/identity/agent_grpc.pb.go index c0f7f20609..af49e8f241 100644 --- a/weaver/common/protos-go/identity/agent_grpc.pb.go +++ b/weaver/common/protos-go/identity/agent_grpc.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.12.4 +// - protoc v3.17.3 // source: identity/agent.proto package identity diff --git a/weaver/common/protos-go/networks/networks.pb.go b/weaver/common/protos-go/networks/networks.pb.go index 9b26730165..377d1b430d 100644 --- a/weaver/common/protos-go/networks/networks.pb.go +++ b/weaver/common/protos-go/networks/networks.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: networks/networks.proto package networks diff --git a/weaver/common/protos-go/networks/networks_grpc.pb.go b/weaver/common/protos-go/networks/networks_grpc.pb.go index a150a6171b..250b64fcb3 100644 --- a/weaver/common/protos-go/networks/networks_grpc.pb.go +++ b/weaver/common/protos-go/networks/networks_grpc.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.12.4 +// - protoc v3.17.3 // source: networks/networks.proto package networks diff --git a/weaver/common/protos-rs/pkg/src/generated/common.ack.rs b/weaver/common/protos-rs/pkg/src/generated/common.ack.rs index 08185356b2..c4f738bddc 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.ack.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.ack.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// This message respresents "ACKs" sent between relay-relay, /// relay-driver and relay-network #[derive(serde::Serialize, serde::Deserialize)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.events.rs b/weaver/common/protos-rs/pkg/src/generated/common.events.rs index 745791664b..5d2ffd24ff 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.events.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.events.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.query.rs b/weaver/common/protos-rs/pkg/src/generated/common.query.rs index 870b27fb3f..65ce10d958 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.query.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.query.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// the payload to define the data that is being requested #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.state.rs b/weaver/common/protos-rs/pkg/src/generated/common.state.rs index dbeb44d563..47e28979f4 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.state.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.state.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// Metadata for a View #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs index 1a89c27a54..a9b21a94f1 100644 --- a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs +++ b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// Data for a View processing by dest-driver #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs index 0e556add31..aefd5c53eb 100644 --- a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs +++ b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs b/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs index 9a9d8617b8..3f9d89fdb0 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs b/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs index 21227fde93..a3d738d3f8 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// Generated client implementations. pub mod data_transfer_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.events.rs b/weaver/common/protos-rs/pkg/src/generated/relay.events.rs index 50785f0d56..d8f258b622 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.events.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.events.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// Generated client implementations. pub mod event_subscribe_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index b7147bd954..69b6df5d89 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts b/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts deleted file mode 100644 index 08b7597980..0000000000 --- a/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import { Gateway, Wallets, Contract, X509Identity } from 'fabric-network' -import { getNetworkConfig, saveUserCertToFile, handlePromise } from './helpers' -import FabricCAServices from 'fabric-ca-client' -import { Certificate } from '@fidm/x509' -import { Utils, ICryptoKey } from 'fabric-common' -import * as membership_pb from "@hyperledger/cacti-weaver-protos-js/common/membership_pb" -import * as iin_agent_pb from "@hyperledger/cacti-weaver-protos-js/identity/agent_pb" -import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric' -import * as path from 'path' -import * as dotenv from 'dotenv' -dotenv.config({ path: path.resolve(__dirname, '../../.env') }) -import * as fs from 'fs' - -export type InvocationSpec = { - contractName: string - channel: string - args: string[] - ccFunc: string -} - -const getUserCertBase64 = async ( - networkName: string, - username: string -) => { - const wallet = await getWalletForNetwork(networkName) - const userId = await wallet.get(username) - if (!userId) { - throw new Error(`User ${username} not present in wallet of ${networkName}.`) - } - return Buffer.from((userId as X509Identity).credentials.certificate).toString('base64') -} - -const walletSetup = async ( - networkName: string, - ccp: any, - mspId: string, - userName: string, - userPwd: string = '', - isNetworkAdmin: boolean = false, - isIINAgent: boolean = false, - register: boolean = false, - logger: any = console -) => { - // Create a new CA client for interacting with the CA. - const org = ccp.client['organization'] - const caName = ccp.organizations[org]['certificateAuthorities'][0] - const caURL = ccp.certificateAuthorities[caName].url - const ca = new FabricCAServices(caURL) - const ident = ca.newIdentityService() - - const wallet = await getWalletForNetwork(networkName) - - // build a user object for authenticating with the CA - // Check to see if we've already enrolled the admin user. - let adminIdentity = await wallet.get('admin') - - if (adminIdentity) { - logger.debug( - 'An identity for the admin user "admin" already exists in the wallet.' - ) - } else { - // Enroll the admin user, and import the new identity into the wallet. - const enrollment = await ca.enroll({ - enrollmentID: 'admin', - enrollmentSecret: 'adminpw' - }) - const x509Identity = { - credentials: { - certificate: enrollment.certificate, - privateKey: enrollment.key.toBytes() - }, - mspId: mspId, - type: 'X.509' - } - await wallet.put('admin', x509Identity) - adminIdentity = await wallet.get('admin') - } - const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type) - const adminUser = await provider.getUserContext(adminIdentity, 'admin') - const identity = await wallet.get(userName) - logger.debug(`user ${userName}`) - if (!identity) { - // Register the user, enroll the user, and import the new identity into the wallet. - if (!register) { - logger.error(`Identity ${userName} does not exist. Please add user in the network.\n`) - return - } - var secret, enrollment - var enrollmentDone = false - var attributes = [] - if (isNetworkAdmin) { - attributes.push({ "name": "network-admin", "value": "true", "ecert": true }) - } - if (isIINAgent) { - attributes.push({ "name": "iin-agent", "value": "true", "ecert": true }) - } - try { - if (!userPwd) { - secret = await ca.register( - { - affiliation: 'org1.department1', - enrollmentID: userName, - maxEnrollments: -1, - role: 'client', - attrs: attributes - }, - adminUser - ) - } - else { - secret = await ca.register( - { - affiliation: 'org1.department1', - enrollmentID: userName, - enrollmentSecret: userPwd, - maxEnrollments: -1, - role: 'client', - attrs: attributes - }, - adminUser - ) - } - logger.info(`Wallet Setup: Sucessful ${secret}`) - } catch(error) { - const registeredUser = `Identity '${userName}' is already ` - if (!userPwd || !(error.message.includes("Identity ") && error.message.includes(userName) && error.message.includes(" is already registered"))) { - throw new Error(`user ${userName} registration with Fabric CA failed with error: ${error}`) - } else { - try { - enrollment = await ca.enroll({ - enrollmentID: userName, - enrollmentSecret: userPwd - }) - enrollmentDone = true - } catch (error) { - throw new Error(`user ${userName} registration/enrollment with Fabric CA failed with error: ${error}`) - } - } - } - - if (!enrollmentDone) { - enrollment = await ca.enroll({ - enrollmentID: userName, - enrollmentSecret: secret - }) - } - - const x509Identity = { - credentials: { - certificate: enrollment.certificate, - privateKey: enrollment.key.toBytes() - }, - mspId: mspId, - type: 'X.509' - } - await wallet.put(userName, x509Identity) - } - else { - logger.debug(`Identity ${userName} already exists.\n`) - } - - return wallet -} - -const enrollAndRecordWalletIdentity = async ( - userName: string, - userPwd: string, - networkName: string, - isNetworkAdmin: boolean = false, - isIINAgent: boolean = false, - logger: any = console -) => { - const net = getNetworkConfig(networkName) - const ccpPath = path.resolve(__dirname, net.connProfilePath) - const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) - logger.info(net) - - const wallet = await walletSetup(networkName, ccp, net.mspId, userName, userPwd, isNetworkAdmin, isIINAgent, true) - saveUserCertToFile(userName, networkName) - - return wallet -} - -const getCurrentNetworkCredentialPath = (networkName: string): string => { - const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER - ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, networkName) - : path.join(__dirname, '../data', 'credentials', networkName) - return credentialsPath -} - -const getCredentialPath = (): string => { - const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER - ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER) - : path.join(__dirname, '../data', 'credentials') - return credentialsPath -} - -const generateAccessControl = async ( - channel: string, - contractName: string, - connProfilePath: string, - networkName: string, - templatePath: string, - username: string, - mspId = global.__DEFAULT_MSPID__, - logger: any = console -): Promise => { - const { wallet } = await fabricHelper({ - channel, - contractName, - connProfilePath, - networkName, - logger, - mspId - }) - const templateJSON = JSON.parse( - Buffer.from(fs.readFileSync(templatePath)).toString() - ) - const [keyCert, keyCertError] = await handlePromise( - getKeyAndCertForRemoteRequestbyUserName(wallet, username) - ) - if (keyCertError) { - logger.error( - 'Error fetching key and certificate from network', - keyCertError - ) - } - const updatedRules = templateJSON.rules.map(rule => { - if (rule.principalType == 'ca') { - rule.principal = mspId - } else if (rule.principalType == 'certificate') { - rule.principal = keyCert.cert - } else { - logger.error( - 'Error Invalid Principal Type in template file' - ) - } - return rule - }) - const accessControlJSON = { - ...templateJSON, - securityDomain: networkName, - rules: updatedRules - } - logger.debug(`AccessControlJSON ${JSON.stringify(accessControlJSON)}`) - const credentialsPath = getCurrentNetworkCredentialPath(networkName) - fs.writeFileSync( - path.join(credentialsPath, `access-control.json`), - JSON.stringify(accessControlJSON) - ) -} - -const generateVerificationPolicy = async ( - channel, - contractName, - connProfilePath, - networkName: string, - templatePath: string, - mspId = global.__DEFAULT_MSPID__, - logger: any = console -): Promise => { - const templateJSON = JSON.parse( - Buffer.from(fs.readFileSync(templatePath)).toString() - ) - const { gateway } = await fabricHelper({ - channel, - contractName, - connProfilePath, - networkName, - mspId, - logger - }) - - const network = await gateway.getNetwork(channel) - const mspConfig = await getMspConfig(network, logger) - const criteria = Object.keys(formatMSP(mspConfig, networkName).members) - const newIdentifiers = templateJSON.identifiers.map(identifier => { - identifier.policy.criteria = criteria - return identifier - }) - const verificationPolicy = { - ...templateJSON, - identifiers: newIdentifiers, - securityDomain: networkName - } - logger.debug(`VerificationPolicyJSON ${JSON.stringify(verificationPolicy)}`) - const credentialsPath = getCurrentNetworkCredentialPath(networkName) - logger.debug('Credential Path', credentialsPath) - fs.writeFileSync( - path.join(credentialsPath, `verification-policy.json`), - JSON.stringify(verificationPolicy) - ) -} - -const generateMembership = async ( - channel: string, - contractName: string, - connProfilePath: string, - networkName: string, - mspId = global.__DEFAULT_MSPID__, - logger: any = console, - iinAgent: boolean = false -): Promise => { - const { gateway } = await fabricHelper({ - channel, - contractName, - connProfilePath, - networkName, - mspId, - logger - }) - - const network = await gateway.getNetwork(channel) - const mspConfig = await getMspConfig(network, logger) - const membershipJSON = formatMSP(mspConfig, networkName) - const membershipJSONStr = JSON.stringify(membershipJSON) - logger.debug(`membershipJSON: ${membershipJSONStr}`) - - const credentialsPath = getCurrentNetworkCredentialPath(networkName) - logger.debug(`Credentials Path: ${credentialsPath}`) - if (!fs.existsSync(credentialsPath)) { - logger.debug(`Creating directory`) - fs.mkdirSync(credentialsPath, { recursive: true }) - } - - fs.writeFileSync( - path.join(credentialsPath, `membership.json`), - membershipJSONStr - ) - - if (iinAgent) { - // Generate protobufs and attestations for all other networks that have IIN Agents - const credentialFolderPath = getCredentialPath() - const otherNetworkNames = fs - .readdirSync(credentialFolderPath, { withFileTypes: true }) - .filter(dirent => dirent.isDirectory()) - .filter(item => item.name.startsWith('network')) // HACK until we add IIN Agents for Corda networks - .map(item => item.name) - // Reorder the array so that the local network is the first element - // We need to record local membership before recording other networks' memberships - otherNetworkNames.splice(otherNetworkNames.indexOf(networkName), 1) - - if (otherNetworkNames.length > 0) { - // Convert membership object to protobuf - let membershipProto = new membership_pb.Membership() - membershipProto.setSecuritydomain(membershipJSON.securityDomain) - Object.keys(membershipJSON.members).forEach( (memberName, index) => { - const certInfo = membershipJSON.members[memberName] - let memberProto = new membership_pb.Member() - memberProto.setType(certInfo.type) - memberProto.setValue(certInfo.value) - membershipProto.getMembersMap().set(memberName, memberProto) - }) - - // For every other network, generate a counter attested membership set - const serializedMembership = membershipProto.serializeBinary() - const serializedMembershipBase64 = Buffer.from(serializedMembership).toString('base64') - const nonce = 'j849j94j40f440fkfjkld0e043' // Some random string - const membershipBase64WithNonce = serializedMembershipBase64 + nonce - // Get wallet key and cert for this network's IIN Agent - const localWallet = await getWalletForNetwork(networkName) - const localKeyCert = await getKeyAndCertForRemoteRequestbyUserName(localWallet, 'iinagent') - // Sign using wallet identity - let securityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() - securityDomainMember.setSecurityDomain(membershipJSON.securityDomain) - securityDomainMember.setMemberId(Object.keys(membershipJSON.members)[0]) - let localAttestation = new iin_agent_pb.Attestation() - localAttestation.setUnitIdentity(securityDomainMember) - localAttestation.setCertificate(localKeyCert.cert) - const localSig = InteroperableHelper.signMessage(membershipBase64WithNonce, localKeyCert.key.toBytes()) - localAttestation.setSignature(localSig) - localAttestation.setNonce(nonce) - let attestedMembershipSet = new iin_agent_pb.CounterAttestedMembership.AttestedMembershipSet() - attestedMembershipSet.setMembership(serializedMembershipBase64) - attestedMembershipSet.setAttestationsList( [ localAttestation ] ) - const serializedAttestedMembershipSet = attestedMembershipSet.serializeBinary() - const serializedttestedMembershipSetBase64 = Buffer.from(serializedAttestedMembershipSet).toString('base64') - const serializedttestedMembershipSetBase64WithNonce = serializedttestedMembershipSetBase64 + nonce - for (const otherNetworkName of otherNetworkNames) { - // Get wallet key and cert for other network's IIN Agent - const otherWallet = await getWalletForNetwork(otherNetworkName) - const otherKeyCert = await getKeyAndCertForRemoteRequestbyUserName(otherWallet, 'iinagent') - // Sign using wallet identity - let otherSecurityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() - otherSecurityDomainMember.setSecurityDomain(otherNetworkName) - otherSecurityDomainMember.setMemberId(getNetworkConfig(otherNetworkName).mspId) - let otherAttestation = new iin_agent_pb.Attestation() - otherAttestation.setUnitIdentity(otherSecurityDomainMember) - otherAttestation.setCertificate(otherKeyCert.cert) - const otherSig = InteroperableHelper.signMessage(serializedttestedMembershipSetBase64WithNonce, otherKeyCert.key.toBytes()) - otherAttestation.setSignature(otherSig) - otherAttestation.setNonce(nonce) - - // Generate chaincode argument and save it in a file - let counterAttestedMembership = new iin_agent_pb.CounterAttestedMembership() - counterAttestedMembership.setAttestedMembershipSet(serializedttestedMembershipSetBase64) - counterAttestedMembership.setAttestationsList( [ otherAttestation ] ) - - fs.writeFileSync( - path.join(credentialsPath, `attested-membership-${otherNetworkName}.proto.serialized`), - Buffer.from(counterAttestedMembership.serializeBinary()).toString('base64') - ) - } - } - } - return membershipJSON -} - -const formatMSP = (mspConfig: MspConfig, networkId: string) => { - const memberObject = { members: {}, securityDomain: networkId } - Object.entries(mspConfig).forEach(([name, value], _) => { - // const cert = Certificate.fromPEM(Buffer.from(value.root_certs[0], 'base64')) - memberObject.members[name] = { - type: 'ca', - value: Buffer.from(value.root_certs[0], 'base64').toString('utf8') - } - }) - return memberObject -} - -type MspConfig = { - [key: string]: { admins: any; root_certs: any; name: string } -} - -const getMspConfig = async ( - network, - logger: any = console -): Promise => { - const mspConfigs = network.channel.getMspids() - const orgMspConfig = {} - logger.debug(mspConfigs) - logger.debug(network.channel.getMsp(mspConfigs[0])) - - mspConfigs.forEach(mspId => { - if (mspId !== 'OrdererMSP') { - logger.info('Getting MSP Info for org with MSP ID: ' + mspId + '.') - const mspConfig = network.getChannel().getMsp(mspId) - delete mspConfig.id - if (Array.isArray(mspConfig.admins)) { - for (let i = 0; i < mspConfig.admins.length; i++) { - mspConfig.admins[i] = Buffer.from(mspConfig.admins[i]).toString( - 'base64' - ) - } - } else if (mspConfig.admins.length === 0) { - mspConfig.admins = [] - } else { - mspConfig.admins = [Buffer.from(mspConfig.admins).toString('base64')] - } - if (Array.isArray(mspConfig.rootCerts)) { - for (let i = 0; i < mspConfig.rootCerts.length; i++) { - mspConfig.rootCerts[i] = Buffer.from(mspConfig.rootCerts[i]).toString( - 'base64' - ) - } - } else if (mspConfig.rootCerts.length === 0) { - mspConfig.rootCerts = [] - } else { - mspConfig.rootCerts = [ - Buffer.from(mspConfig.rootCerts).toString('base64') - ] - } - mspConfig.root_certs = mspConfig.rootCerts - delete mspConfig.rootCerts - if (Array.isArray(mspConfig.intermediateCerts)) { - for (let i = 0; i < mspConfig.intermediateCerts.length; i++) { - mspConfig.intermediateCerts[i] = Buffer.from( - mspConfig.intermediateCerts[i] - ).toString('base64') - } - } else if (mspConfig.intermediateCerts.length === 0) { - mspConfig.intermediateCerts = [] - } else { - mspConfig.intermediateCerts = [ - Buffer.from(mspConfig.intermediateCerts).toString('base64') - ] - } - mspConfig.intermediate_certs = mspConfig.intermediateCerts - delete mspConfig.intermediateCerts - if (Array.isArray(mspConfig.tlsRootCerts)) { - for (let i = 0; i < mspConfig.tlsRootCerts.length; i++) { - mspConfig.tlsRootCerts[i] = Buffer.from( - mspConfig.tlsRootCerts[i] - ).toString('base64') - } - } else if (mspConfig.tlsRootCerts.length === 0) { - mspConfig.tlsRootCerts = [] - } else { - mspConfig.tlsRootCerts = [ - Buffer.from(mspConfig.tlsRootCerts).toString('base64') - ] - } - mspConfig.tls_root_certs = mspConfig.tlsRootCerts - delete mspConfig.tlsRootCerts - if (Array.isArray(mspConfig.tlsIntermediateCerts)) { - for (let i = 0; i < mspConfig.tlsIntermediateCerts.length; i++) { - mspConfig.tlsIntermediateCerts[i] = Buffer.from( - mspConfig.tlsIntermediateCerts[i] - ).toString('base64') - } - } else if (mspConfig.tlsIntermediateCerts.length === 0) { - mspConfig.tlsIntermediateCerts = [] - } else { - mspConfig.tlsIntermediateCerts = [ - Buffer.from(mspConfig.tlsIntermediateCerts).toString('base64') - ] - } - mspConfig.tls_intermediate_certs = mspConfig.tlsIntermediateCerts - delete mspConfig.tlsIntermediateCerts - orgMspConfig[mspId] = mspConfig - } - }) - return orgMspConfig -} - -async function fabricHelper({ - channel, - contractName, - connProfilePath, - networkName, - mspId = global.__DEFAULT_MSPID__, - logger = console, - discoveryEnabled = true, - userString = '', - userPwd = '', - registerUser = true -}: { - channel: string - contractName: string - connProfilePath: string - networkName: string - mspId?: string - discoveryEnabled?: boolean - logger?: any - userString?: string - userPwd?: string - registerUser?: boolean -}): Promise<{ gateway: Gateway; contract: Contract; wallet: any }> { - // load the network configuration - const ccpPath = path.resolve(__dirname, connProfilePath) - const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) - // Create a new file system based wallet for managing identities. - // const walletPath = process.env.WALLET_PATH - // ? process.env.WALLET_PATH - // : path.join(__dirname, '../', `wallet-${networkName}`) - - if (!userString) { - userString = `user1` - userPwd = `user1pw` - } - - const wallet = await walletSetup(networkName, ccp, mspId, userString, userPwd, false, false, registerUser, logger) - // Check to see if we've already enrolled the user. - const identity = await wallet.get(userString) - if (!identity) { - logger.info( - `An identity for the user "${userString}" does not exist in the wallet` - ) - logger.info('Run the registerUser.ts application before retrying') - } - // Create a new gateway for connecting to our peer node. - const gateway = new Gateway() - await gateway.connect(ccp, { - wallet, - identity: identity, - discovery: { - enabled: discoveryEnabled, - asLocalhost: process.env.LOCAL === 'false' ? false : true - } - }) - const network = await gateway.getNetwork(channel) - // Get the contract from the network. - const contract = network.getContract(contractName) - return { gateway, contract, wallet } -} - -async function query( - invocationSpec: InvocationSpec, - connProfilePath: string, - networkName: string, - mspId = global.__DEFAULT_MSPID__, - logger: any = console, - userString = '', - registerUser = true -): Promise { - logger.debug('Running invoke on fabric network') - try { - logger.debug( - `QUERY: ${JSON.stringify( - invocationSpec - )} connProfilePath: ${connProfilePath} networkName ${networkName} ` - ) - const { contract, gateway } = await fabricHelper({ - channel: invocationSpec.channel, - contractName: invocationSpec.contractName, - connProfilePath: connProfilePath, - networkName: networkName, - mspId: mspId, - logger: logger, - userString: userString, - registerUser: registerUser - }) - const read = await contract.evaluateTransaction(invocationSpec.ccFunc, ...invocationSpec.args) - const state = Buffer.from(read).toString() - if (state) { - logger.debug(`State From Network:`, state) - } else { - logger.debug(`No State from network`) - } - // Disconnect from the gateway. - await gateway.disconnect() - return state - } catch (error) { - logger.error(`Failed to submit transaction: ${error}`) - throw new Error(error) - } -} - -async function invoke( - invocationSpec: InvocationSpec, - connProfilePath: string, - networkName: string, - mspId = global.__DEFAULT_MSPID__, - logger: any = console, - userString = '', - registerUser = true -): Promise { - logger.debug('Running invoke on fabric network') - try { - const { contract, gateway } = await fabricHelper({ - channel: invocationSpec.channel, - contractName: invocationSpec.contractName, - connProfilePath: connProfilePath, - networkName: networkName, - mspId: mspId, - logger: logger, - userString: userString, - registerUser: registerUser - }) - logger.debug( - `CCFunc: ${invocationSpec.ccFunc} 'CCArgs: ${JSON.stringify(invocationSpec.args)}` - ) - const read = await contract.submitTransaction(invocationSpec.ccFunc, ...invocationSpec.args) - const state = Buffer.from(read).toString() - if (state) { - logger.debug(`Response From Network: ${state}`) - } else { - logger.debug('No Response from network') - } - - // Disconnect from the gateway. - await gateway.disconnect() - return state - } catch (error) { - console.error(`Failed to submit transaction: ${error}`) - throw new Error(error) - } -} - -const getKeyAndCertForRemoteRequestbyUserName = async ( - wallet: any, - username: string -): Promise<{ key: ICryptoKey; cert: any }> => { - if (!wallet) { - throw new Error('No wallet passed') - } - if (!username) { - throw new Error('No username passed') - } - const identity = await wallet.get(username) - if (!identity) { - throw new Error( - 'Identity for username ' + username + ' not present in wallet' - ) - } - // Assume the identity is of type 'fabric-network.X509Identity' - const privKey = Utils.newCryptoSuite().createKeyFromRaw( - identity.credentials.privateKey - ) - return { key: privKey, cert: identity.credentials.certificate } -} - -const getWalletForNetwork = async ( - networkName: string, -) => { - const walletPath = process.env.WALLET_PATH - ? process.env.WALLET_PATH - : path.join(__dirname, '../', `wallet-${networkName}`) - - const wallet = await Wallets.newFileSystemWallet(walletPath) - return wallet -} - - -export { - getUserCertBase64, - walletSetup, - invoke, - query, - enrollAndRecordWalletIdentity, - fabricHelper, - generateMembership, - generateAccessControl, - getKeyAndCertForRemoteRequestbyUserName, - getCredentialPath, - getCurrentNetworkCredentialPath, - generateVerificationPolicy -} diff --git a/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts b/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts deleted file mode 100644 index 624164d8be..0000000000 --- a/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import { getKeyAndCertForRemoteRequestbyUserName, fabricHelper, invoke, query, InvocationSpec } from './fabric-functions' -import { AssetPledge } from "@hyperledger/cacti-weaver-protos-js/common/asset_transfer_pb" -import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric' -import * as crypto from 'crypto' -import { promisify } from 'util' -import * as fs from 'fs' -import * as path from 'path' -import * as dotenv from 'dotenv' -import logger from './logger' -dotenv.config({ path: path.resolve(__dirname, '../../.env') }) - - -// UPDATE Following if new env variable or config variable is added. -// Valid keys for .env -const validKeys = [ - 'DEFAULT_CHANNEL', - 'DEFAULT_CHAINCODE', - 'MEMBER_CREDENTIAL_FOLDER', - 'LOCAL', - 'DEFAULT_APPLICATION_CHAINCODE', - 'CONFIG_PATH', - 'REMOTE_CONFIG_PATH', - 'CHAINCODE_PATH' -] -// Valid keys for config -const configKeys = ['connProfilePath', 'relayEndpoint', 'mspId', 'channelName', 'chaincode', 'aclPolicyPrincipalType'] - -const signMessage = (message, privateKey) => { - const sign = crypto.createSign('sha256') - sign.write(message) - sign.end() - return sign.sign(privateKey) -} - -// Basic function to add assets to network, it assumes function is CreateAsset -// TODO: Pass function name as parameter -const addAssets = ({ - dataFilePath, - networkName, - connProfilePath, - invocationSpec, - mspId = global.__DEFAULT_MSPID__, - channelName, - contractName, - ccFunc, - ccType, - logger -}: { - dataFilePath: string - networkName: string - connProfilePath: string - invocationSpec?: InvocationSpec - mspId?: string - channelName?: string - contractName?: string - ccFunc?: string - ccType: string - logger?: any -}): void => { - const filepath = path.resolve(dataFilePath) - const data = JSON.parse(fs.readFileSync(filepath).toString()) - const valuesList = Object.entries(data) - valuesList.forEach(async (item: [string, string]) => { - const currentQuery = invocationSpec - ? invocationSpec - : { - channel: channelName, - contractName: contractName - ? contractName - : 'simpleasset', - ccFunc: '', - args: [] - } - - const { gateway, contract, wallet } = await fabricHelper({ - channel: channelName, - contractName: contractName, - connProfilePath: connProfilePath, - networkName: networkName, - mspId: mspId, - userString: item[1]['owner'], - registerUser: false - }) - const userId = await wallet.get(item[1]['owner']) - const userCert = Buffer.from((userId).credentials.certificate).toString('base64') - - if (ccType == 'bond') { - currentQuery.ccFunc = 'CreateAsset' - currentQuery.args = [...currentQuery.args, item[1]['assetType'], item[1]['id'], userCert, item[1]['issuer'], item[1]['facevalue'], item[1]['maturitydate']] - } else if (ccType == 'token') { - currentQuery.ccFunc = 'IssueTokenAssets' - currentQuery.args = [...currentQuery.args, item[1]['tokenassettype'], item[1]['numunits'], userCert] - } else { - throw new Error(`Unrecognized asset category: ${ccType}`) - } - console.log(currentQuery) - try { - const read = await contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) - const state = Buffer.from(read).toString() - if (state) { - logger.debug(`Response From Network: ${state}`) - } else { - logger.debug('No Response from network') - } - - // Disconnect from the gateway. - await gateway.disconnect() - return state - } catch (error) { - console.error(`Failed to submit transaction: ${error}`) - throw new Error(error) - } - }) -} - - -// Basic function to pledge an asset in one network to another, it assumes function is PledgeAsset -// TODO: Pass function name as parameter -const pledgeAsset = async ({ - dataFilePath, - sourceNetworkName, - destNetworkName, - recipient, - expirySecs, - connProfilePath, - invocationSpec, - mspId = global.__DEFAULT_MSPID__, - channelName, - contractName, - ccFunc, - ccType, - assetOwner, - assetRef, - assetUnits, - logger -}: { - dataFilePath: string - sourceNetworkName: string - destNetworkName: string - recipient: string - expirySecs: number - connProfilePath: string - invocationSpec?: InvocationSpec - mspId?: string - channelName?: string - contractName?: string - ccFunc?: string - ccType: string - assetOwner: string - assetRef: string - assetUnits: number - logger?: any -}): Promise => { - const filepath = path.resolve(dataFilePath) - const data = JSON.parse(fs.readFileSync(filepath).toString()) - let item - if (assetRef) { - item = data[assetRef] - if (!item) { - throw new Error(`Cannot find asset ref ${assetRef} in file ${filepath}`) - } - } else if (assetOwner) { - item = data[assetOwner] - if (!item) { - throw new Error(`Cannot find asset owner ${assetOwner} in file ${filepath}`) - } - } else { - throw new Error(`Neither asset owner nor reference is supplied`) - } - const currentQuery = invocationSpec - ? invocationSpec - : { - channel: channelName, - contractName: contractName - ? contractName - : 'simpleasset', - ccFunc: '', - args: [] - } - - const { gateway, contract, wallet } = await fabricHelper({ - channel: channelName, - contractName: contractName, - connProfilePath: connProfilePath, - networkName: sourceNetworkName, - mspId: mspId, - userString: item['owner'], - registerUser: false - }) - const recipientCert = getUserCertFromFile(recipient, destNetworkName) - const expirationTime = (Math.floor(Date.now()/1000 + expirySecs)).toString() - - if (ccType == 'bond') { - currentQuery.ccFunc = 'PledgeAsset' - currentQuery.args = [...currentQuery.args, item['assetType'], item['id'], destNetworkName, recipientCert, expirationTime] - } else if (ccType == 'token') { - currentQuery.ccFunc = 'PledgeTokenAsset' - currentQuery.args = [...currentQuery.args, item['tokenassettype'], '' + assetUnits, destNetworkName, recipientCert, expirationTime] - } else { - throw new Error(`Unrecognized/unsupported asset category: ${ccType}`) - } - console.log(currentQuery) - try { - const read = await contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) - const state = Buffer.from(read).toString() - if (state) { - logger.debug(`Response From Network: ${state}`) - } else { - logger.debug('No Response from network') - } - - // Disconnect from the gateway. - await gateway.disconnect() - return state - } catch (error) { - console.error(`Failed to submit transaction: ${error}`) - throw new Error(error) - } -} - -// Used to obtain remote network user certificate from '${networkId}_UsersAndCerts.json' file. -// This is called during Pledge to get the recipientCert, and during Claim to get the pledgerCert. -const getUserCertFromFile = ( - remoteUser: string, - remoteNetworkId: string -) => { - const usersAndCertsFile = remoteNetworkId + '_UsersAndCerts.json' - const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER - ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, '..') - : path.join(__dirname, '../data', 'credentials', '..') - try { - const dirPath = path.resolve(credentialsPath, 'remoteNetworkUsers') - const filepath = path.resolve(dirPath, usersAndCertsFile) - const usersAndCertsJSON = JSON.parse(fs.readFileSync(filepath).toString()) - logger.debug(`credentialsPath: ${credentialsPath} and usersAndCertsFile: ${usersAndCertsFile}`) - - if (!usersAndCertsJSON[remoteUser]) { - logger.error( - `User: ${remoteUser} does not exist in the file ${usersAndCertsFile}.` - ) - return '' - } - logger.debug(`remoteUser: ${remoteUser} and certificate: ${usersAndCertsJSON[remoteUser]}`) - return usersAndCertsJSON[remoteUser] - } catch (err) { - logger.error(`User: ${remoteUser} does not exist in the file ${usersAndCertsFile}.`) - return '' - } -} - -// Used to store the network user certificate to the file '${networkId}_UsersAndCerts.json'. -// This is used during Pledge to get the recipientCert, and during Claim to get the pledgerCert. -const saveUserCertToFile = ( - remoteUser: string, - remoteNetworkId: string -) => { - const usersAndCertsFile = remoteNetworkId + '_UsersAndCerts.json' - let usersAndCertsJSON = {} - const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER - ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, '..') - : path.join(__dirname, '../data', 'credentials', '..') - // Don't create the directory 'remoteNetworkUsers' inside 'data/credentials' since each entry there represents - // a network. Instead, create this directory inside 'data' itself. - try { - const dirPath = path.resolve(credentialsPath, 'remoteNetworkUsers') - const filepath = path.resolve(dirPath, usersAndCertsFile) - logger.debug(`credentialsPath: ${credentialsPath} and usersAndCertsFile: ${usersAndCertsFile}`) - - if (!fs.existsSync(dirPath)) { - logger.debug(`Creating directory ${dirPath}`) - fs.mkdirSync(dirPath, { recursive: true }) - } - - if (fs.existsSync(filepath)) { - logger.debug(`Reading contents of the file ${filepath}`) - usersAndCertsJSON = JSON.parse(fs.readFileSync(filepath).toString()) - } - - const remoteUserId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + remoteNetworkId + '/' + remoteUser + '.id').toString()) - const remoteUserCertBase64 = Buffer.from(remoteUserId.credentials.certificate).toString('base64') - - usersAndCertsJSON[remoteUser] = remoteUserCertBase64 - fs.writeFileSync( - path.resolve(filepath), - JSON.stringify(usersAndCertsJSON) - ) - } catch (err) { - logger.error(`User: ${remoteUser} certificate cannot be saved to the file ${usersAndCertsFile}.`) - } -} - -// Basic function to query asset pledge details from a network, it assumes function is GetAssetPledgeStatus -// TODO: Pass function name as parameter -const getAssetPledgeDetails = async ({ - sourceNetworkName, - pledger, - pledgerCert, - destNetworkName, - recipient, - recipientCert, - invocationSpec, - mspId = global.__DEFAULT_MSPID__, - ccFunc, - pledgeId, - logger -}: { - sourceNetworkName: string - pledger: string - pledgerCert: string - destNetworkName: string - recipient: string - recipientCert: string - invocationSpec?: InvocationSpec - mspId?: string - ccFunc?: string - pledgeId: string - logger?: any -}): Promise => { - const netConfig = getNetworkConfig(sourceNetworkName) - - const currentQuery = invocationSpec - ? invocationSpec - : { - channel: netConfig.channelName, - contractName: netConfig.chaincode - ? netConfig.chaincode - : 'simpleasset', - ccFunc: '', - args: [] - } - - const { gateway, contract, wallet } = await fabricHelper({ - channel: netConfig.channelName, - contractName: netConfig.chaincode, - connProfilePath: netConfig.connProfilePath, - networkName: sourceNetworkName, - mspId: netConfig.mspId, - userString: pledger, - registerUser: false - }) - if (!pledgerCert) { - const pledgerId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + sourceNetworkName + '/' + pledger + '.id').toString()) - pledgerCert = Buffer.from(pledgerId.credentials.certificate).toString('base64') - } - if (!recipientCert) { - const recipientId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + destNetworkName + '/' + recipient + '.id').toString()) - recipientCert = Buffer.from(recipientId.credentials.certificate).toString('base64') - } - - currentQuery.ccFunc = 'GetAssetPledgeStatus' - currentQuery.args = [...currentQuery.args, pledgeId, pledgerCert, destNetworkName, recipientCert] - console.log(currentQuery) - try { - const read = await contract.evaluateTransaction(currentQuery.ccFunc, ...currentQuery.args) - const state = Buffer.from(read).toString() - if (state) { - logger.debug(`Response From Network: ${state}`) - } else { - logger.debug('No Response from network') - } - - // Disconnect from the gateway. - await gateway.disconnect() - return state - } catch (error) { - console.error(`Failed to submit transaction: ${error}`) - throw new Error(error) - } -} - -// Basic function to query asset pledge details from a network, it assumes function is GetAssetPledgeDetails -// TODO: Pass function name as parameter -const getLocalAssetPledgeDetails = async ({ - sourceNetworkName, - pledgeId, - caller, - ccType, - ccFunc, - logger -}: { - sourceNetworkName: string - pledgeId: string - caller: string - ccType?: string - ccFunc?: string - logger?: any -}): Promise => { - const netConfig = getNetworkConfig(sourceNetworkName) - - const currentQuery = { - channel: netConfig.channelName, - contractName: netConfig.chaincode - ? netConfig.chaincode - : 'simpleasset', - ccFunc: '', - args: [] - } - - if (ccFunc) { - currentQuery.ccFunc = ccFunc - } else if (ccType && ccType == 'token') { - currentQuery.ccFunc = 'GetTokenAssetPledgeDetails' - } else { - currentQuery.ccFunc = 'GetAssetPledgeDetails' - } - currentQuery.args = [...currentQuery.args, pledgeId] - console.log(currentQuery) - try { - const pledgeDetails = await query(currentQuery, - netConfig.connProfilePath, - sourceNetworkName, - netConfig.mspId, - logger, - caller, - false - ) - const pledgeDetailBytes = Buffer.from(pledgeDetails, 'base64') - const pledgeDetailsProto = AssetPledge.deserializeBinary(pledgeDetailBytes) - return pledgeDetailsProto - } catch (error) { - console.error(`Failed to get pledge details: ${error}`) - throw new Error(error) - } -} - -// Basic function to add data to network, it assumes function is Create -// TODO: Pass function name as parameter -const addData = ({ - filename, - networkName, - connProfilePath, - invocationSpec, - mspId = global.__DEFAULT_MSPID__, - logger -}: { - filename: string - networkName: string - connProfilePath: string - invocationSpec?: InvocationSpec - mspId?: string - logger?: any -}): void => { - const filepath = path.resolve(__dirname, '..', 'data', filename) - const data = JSON.parse(fs.readFileSync(filepath).toString()) - const valuesList = Object.entries(data) - valuesList.forEach((item: [string, string]) => { - const currentQuery = invocationSpec - ? invocationSpec - : { - channel: process.env.DEFAULT_CHANNEL - ? process.env.DEFAULT_CHANNEL - : 'mychannel', - contractName: process.env.DEFAULT_APPLICATION_CHAINCODE - ? process.env.DEFAULT_APPLICATION_CHAINCODE - : 'simplestate', - ccFunc: process.env.DEFAULT_APPLICATION_FUNC - ? process.env.DEFAULT_APPLICATION_FUNC - : 'Create', - args: [] - } - currentQuery.args = [...currentQuery.args, item[0], item[1]] - invoke(currentQuery, connProfilePath, networkName, mspId, logger) - }) -} - -// A better way to handle errors for promises -function handlePromise(promise: Promise): Promise<[T?, Error?]> { - const result: Promise<[T?, Error?]> = promise - .then(data => { - const response: [T?, Error?] = [data, undefined] - return response - }) - .catch(error => Promise.resolve([undefined, error])) - return result -} - -// Necessary until gRPC provides a native async friendly solution https://github.com/grpc/grpc-node/issues/54 -function promisifyAll(client): any { - const to = {} - for (const k in client) { - if (typeof client[k] != 'function') continue - to[k] = promisify(client[k].bind(client)) - } - return to -} - -const readJSONFromFile = (jsonfile, logger = console) => { - let data = null - const filepath = path.resolve(jsonfile) - logger.debug('jsonfile is ' + jsonfile) - logger.debug('filepath is ' + filepath) - - try { - const contents = fs.readFileSync(filepath).toString() - logger.debug('contents ' + contents) - data = JSON.parse(contents) - logger.debug('data - ' + JSON.stringify(data)) - } catch (e) { - logger.debug('Error ' + e.message + ' while parsing JSON config file') - throw e - } - return data -} - -// Used for getting network configuration from config.json file. -const getNetworkConfig = ( - networkId: string -): { relayEndpoint?: string; connProfilePath: string; username?: string; mspId?:string; aclPolicyPrincipalType?: string; channelName?: string; chaincode?: string } => { - const configPath = process.env.CONFIG_PATH - ? path.join(process.env.CONFIG_PATH) - : path.join(__dirname, '../../config.json') - try { - const configJSON = JSON.parse(fs.readFileSync(configPath).toString()) - if (!configJSON[networkId]) { - logger.error( - `Network: ${networkId} does not exist in the config.json file` - ) - return { relayEndpoint: '', connProfilePath: '', username: '', mspId: '', aclPolicyPrincipalType: '', channelName: '', chaincode: '' } - } - return configJSON[networkId] - } catch (err) { - logger.error(`Network: ${networkId} does not exist in the config.json file`) - return { relayEndpoint: '', connProfilePath: '', username: '', mspId: '', aclPolicyPrincipalType: '', channelName: '', chaincode: '' } - } -} - -// Used for getting network configuration from config.json file. -const getChaincodeConfig = ( - chaincodeId: string, - chaincodeFunc: string -): { args: Array; replaceIndices: Array } => { - const ccPath = process.env.CHAINCODE_PATH - ? path.join(process.env.CHAINCODE_PATH) - : path.join(__dirname, '../../chaincode.json') - try { - const ccJSON = JSON.parse(fs.readFileSync(ccPath).toString()) - if (!ccJSON[chaincodeId]) { - logger.error( - `Chaincode: ${chaincodeId} does not exist in the chaincode.json file` - ) - return { args: [], replaceIndices: [] } - } - if (!ccJSON[chaincodeId][chaincodeFunc]) { - logger.error( - `Chaincode: ${chaincodeId} does not have a ${chaincodeFunc} function attribute in the chaincode.json file` - ) - return { args: [], replaceIndices: [] } - } - return ccJSON[chaincodeId][chaincodeFunc] - } catch (err) { - logger.error(`Chaincode: ${chaincodeId} does not exist in the chaincode.json file`) - return { args: [], replaceIndices: [] } - } -} - -// Update view address if needed -const generateViewAddress = async ( - viewAddress: string, - sourceNetwork: string, - destNetwork: string, - logger?: any -): Promise => { - if (!viewAddress || viewAddress.length === 0) { - throw new Error('Empty view address') - } - if (viewAddress.indexOf('#') >= 0) { - return viewAddress - } - if (viewAddress.indexOf('GetAssetClaimStatus') >= 0 || viewAddress.indexOf('GetTokenAssetClaimStatus') >= 0) { - // Get asset pledge details - let ccFunc - if (viewAddress.indexOf('GetAssetClaimStatus') >= 0) { - ccFunc = 'GetAssetClaimStatus' - } else { - ccFunc = 'GetTokenAssetClaimStatus' - } - const addressParts = viewAddress.substring(viewAddress.indexOf(ccFunc) + ccFunc.length + 1).split(':') - if (addressParts.length != 6) { - throw new Error(`Expected 6 arguments for ${ccFunc}; found ${addressParts.length}`) - } - if (addressParts[5] != sourceNetwork) { - throw new Error(`Passed source network ID ${sourceNetwork} does not match last chaincode argument in view address ${addressParts[5]}`) - } - const pledgeDetails = await getAssetPledgeDetails({ - sourceNetworkName: addressParts[5], - pledger: '', - pledgerCert: addressParts[4], - destNetworkName: destNetwork, - recipient: '', - recipientCert: addressParts[3], - pledgeId: addressParts[0], - logger: logger - }) - return viewAddress + ':' + deserializeAssetPledge(pledgeDetails).getExpirytimesecs() - } else { - return viewAddress - } -} - -function deserializeAssetPledge(pledgeDetails) { - const pledgeDetailBytes = Buffer.from(pledgeDetails, 'base64') - const pledgeDetailsProto = AssetPledge.deserializeBinary(pledgeDetailBytes) - return pledgeDetailsProto -} - -// Used for creating view address for interop call using remote-network-config.json -const generateViewAddressFromRemoteConfig = ( - networkId: string, - funcName: string, - funcArgs: Array -): any => { - const configPath = process.env.REMOTE_CONFIG_PATH - ? path.join(process.env.REMOTE_CONFIG_PATH) - : path.join(__dirname, '../../remote-network-config.json') - try { - const configJSON = JSON.parse(fs.readFileSync(configPath).toString()) - if (!configJSON[networkId]) { - logger.error( - `Error: ${networkId} does not exist in the remote-network-config.json file` - ) - throw new Error(`Error: ${networkId} does not exist in the remote-network-config.json file`) - } - - const remoteNetConfig = configJSON[networkId] - let address = remoteNetConfig.relayEndpoint + '/' + networkId - if (remoteNetConfig.type == "fabric") { - address = address + '/' + remoteNetConfig.channelName + ':' + - remoteNetConfig.chaincode + ':' + funcName + ':' + funcArgs.join(':') - } else if (remoteNetConfig.type == "corda") { - address = address + '/' + remoteNetConfig.partyEndPoint + '#' + - remoteNetConfig.flowPackage + "." + funcName + ":" + funcArgs.join(':') - } else { - logger.error(`Error: remote network ${remoteNetConfig.type} not supported.`) - throw new Error(`Error: remote network ${remoteNetConfig.type} not supported.`) - } - console.log(`Interop query, funcName: ${funcName} \n funcArgs: ${funcArgs} \n and address: ${address}`) - - return address - } catch (err) { - logger.error(`Error: ${err}`) - throw new Error(err) - } -} - - -// Used for creating view address for interop call using remote-network-config.json -const interopHelper = async ( - networkName: string, - viewAddress: string, - appChaincodeId: string, - applicationFunction: string, - applicationArgs: Array, - replaceIndices: Array, - options: any, // For TLS -): Promise => { - const netConfig = getNetworkConfig(networkName) - if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { - throw new Error(`No valid config entry found for ${networkName}`) - } - - const { gateway, wallet, contract } = await fabricHelper({ - channel: netConfig.channelName, - contractName: process.env.DEFAULT_CHAINCODE ? process.env.DEFAULT_CHAINCODE : 'interop', - connProfilePath: netConfig.connProfilePath, - networkName, - mspId: netConfig.mspId, - logger, - discoveryEnabled: true, - userString: options['user'] - }) - - const [keyCert, keyCertError] = await handlePromise( - getKeyAndCertForRemoteRequestbyUserName(wallet, options['user']) - ) - if (keyCertError) { - throw new Error(`Error getting key and cert ${keyCertError}`) - } - logger.info(`Starting Interop Query`) - - let relayTlsCAFiles = [] - if (options['relay-tls-ca-files']) { - relayTlsCAFiles = options['relay-tls-ca-files'].split(':') - } - try { - const invokeObject = { - channel: netConfig.channelName, - ccFunc: applicationFunction, - ccArgs: applicationArgs, - contractName: appChaincodeId - } - console.log(invokeObject) - const interopFlowResponse = await InteroperableHelper.interopFlow( - //@ts-ignore this comment can be removed after using published version of interop-sdk - contract, - networkName, - invokeObject, - netConfig.mspId, - netConfig.relayEndpoint, - replaceIndices, - [{ - address: viewAddress, - Sign: true - }], - keyCert, - [], - false, - options['relay-tls'] === 'true', - relayTlsCAFiles, - options['e2e-confidentiality'] === 'true', - gateway - ) - logger.info( - `View from remote network: ${JSON.stringify( - interopFlowResponse.views[0].toObject() - )}. Interop Flow result: ${interopFlowResponse.result || 'successful'}` - ) - logger.debug(`ViewB64: ${Buffer.from(interopFlowResponse.views[0].serializeBinary()).toString('base64')}`) - const remoteValue = (options['e2e-confidentiality'] === 'true' ? - InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0], keyCert.key.toBytes()) : - InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0]) - ) - if (remoteValue.contents) { - logger.debug(`ViewB64Contents: ${Buffer.from(remoteValue.contents).toString('base64')}`) - } - logger.info( - `Called Function ${applicationFunction}. With Args: ${invokeObject.ccArgs} ${remoteValue.data}` - ) - await gateway.disconnect() - return remoteValue.data - } catch (e) { - logger.error(`Error verifying and storing state`) - logger.error(`Error verifying and storing state: ${e}`) - return "" - } -} - - - -export { - addData, - handlePromise, - promisifyAll, - readJSONFromFile, - signMessage, - getNetworkConfig, - getUserCertFromFile, - saveUserCertToFile, - getChaincodeConfig, - validKeys, - configKeys, - addAssets, - pledgeAsset, - getAssetPledgeDetails, - getLocalAssetPledgeDetails, - generateViewAddress, - generateViewAddressFromRemoteConfig, - interopHelper -} diff --git a/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts b/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts deleted file mode 100644 index b85bbc1db6..0000000000 --- a/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as fs from 'fs' -import * as path from 'path' -import { - invoke, - getCurrentNetworkCredentialPath, - getCredentialPath, - fabricHelper -} from '../fabric-functions' -import { handlePromise, getNetworkConfig } from '../helpers' -import { MembershipManager } from '@hyperledger/cacti-weaver-sdk-fabric' - -const helperInvoke = async (userId, ccFunc, ccArg, ...args) => { - const [contractName, channelName, connProfilePath, networkName, logger] = args - const [invokeResponse, invokeError] = await handlePromise( - invoke( - { - contractName, - channel: channelName, - ccFunc: ccFunc, - args: [ccArg] - }, - connProfilePath, - networkName, - global.__DEFAULT_MSPID__, - logger, - userId, - (userId === '') - ) - ) - logger.debug(`${ccFunc} Invoke ${JSON.stringify(invokeResponse)}`) - if (invokeError) { - logger.error(`${ccFunc} Invoke Error: ${ccFunc}: ${ccArg}`) - throw new Error(`${ccFunc} Invoke Error ${invokeError}`) - } else { - logger.info(`Successfully invoked ${ccFunc}`) - } -} - -const configureNetwork = async (mainNetwork: string, members: Array = [global.__DEFAULT_MSPID__], logger: any = console, iinAgent: boolean = false) => { - const networkEnv = getNetworkConfig(mainNetwork) - logger.debug(`NetworkEnv: ${JSON.stringify(networkEnv)}`) - if (!networkEnv.relayEndpoint || !networkEnv.connProfilePath) { - logger.error( - 'Please use a valid --local-network. If valid network please check if your environment variables are configured properly' - ) - return - } - - const credentialFolderPath = getCredentialPath() - const networkFolders = fs - .readdirSync(credentialFolderPath, { withFileTypes: true }) - .filter(dirent => dirent.isDirectory()) - .map(item => item.name) - // Reorder the array so that the local network is the first element - // We need to record local membership before recording other networks' memberships - networkFolders.splice(networkFolders.indexOf(mainNetwork), 1) - networkFolders.splice(0, 0, mainNetwork) - - for (const index in networkFolders) { - const network = networkFolders[index] - if (network === mainNetwork) { - // A network needs to load/record only other networks' credentials - await loadLocalHelper( - networkEnv.connProfilePath, - mainNetwork, - process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', - process.env.DEFAULT_CHAINCODE - ? process.env.DEFAULT_CHAINCODE - : 'interop', - members, - logger - ) - continue; - } - const accessControlPath = path.join( - getCurrentNetworkCredentialPath(network), - 'access-control.json' - ) - let membershipPath = "" - if (!network.startsWith('network')) { - membershipPath = path.join( - getCurrentNetworkCredentialPath(network), - 'membership.json' - ) - } else if (iinAgent) { - membershipPath = path.join( - getCurrentNetworkCredentialPath(network), - 'attested-membership-' + mainNetwork + '.proto.serialized' - ) - } - const verificationPolicyPath = path.join( - getCurrentNetworkCredentialPath(network), - 'verification-policy.json' - ) - if ( - !fs.existsSync(accessControlPath) || - !fs.existsSync(verificationPolicyPath) || - (membershipPath !== "" && !fs.existsSync(membershipPath)) - ) { - logger.error(`Missing credential file for network: ${network}`) - } else { - await configureNetworkHelper( - networkEnv.connProfilePath, - mainNetwork, - process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', - process.env.DEFAULT_CHAINCODE - ? process.env.DEFAULT_CHAINCODE - : 'interop', - network, - accessControlPath, - membershipPath, - verificationPolicyPath, - logger, - iinAgent - ) - } - } -} - -const loadLocalHelper = async ( - connProfilePath: string, - networkName: string, - channelName: string, - contractName: string, - members: Array, - logger: any = console -): Promise => { - //const localMembership = Buffer.from(fs.readFileSync(localMembershipPath)).toString() - const { gateway } = await fabricHelper({ - channel: channelName, - contractName: contractName, - connProfilePath: connProfilePath, - networkName: networkName, - mspId: global.__DEFAULT_MSPID__, - userString: 'networkadmin', - registerUser: false - }) - try { - const response = await MembershipManager.createLocalMembership(gateway, members, networkName, channelName, contractName) - logger.info('CreateLocalMembership Successful.') - } catch (e) { - logger.error(e) - logger.info('CreateLocalMembership attempting Update') - const response = await MembershipManager.updateLocalMembership(gateway, members, networkName, channelName, contractName) - logger.info('Update Local Memebrship response: success: ', response) - } -} - -const configureNetworkHelper = async ( - connProfilePath: string, - networkName: string, - channelName: string, - contractName: string, - targetNetwork: string, - accessControlPath: string, - membershipPath: string, - verificationPolicyPath: string, - logger: any = console, - iinAgent: boolean = false -): Promise => { - logger.info(`Target Network: ${targetNetwork}`) - const accessControl = Buffer.from( - fs.readFileSync(accessControlPath) - ).toString() - - const verificationPolicy = Buffer.from( - fs.readFileSync(verificationPolicyPath) - ).toString() - - const helperInvokeArgs = [ - contractName, - channelName, - connProfilePath, - networkName, - logger - ] - - const adminUser = 'networkadmin' - - try { - await helperInvoke( - adminUser, - 'CreateAccessControlPolicy', - accessControl, - ...helperInvokeArgs - ) - } catch (e) { - logger.info('CreateAccessControlPolicy attempting Update') - await helperInvoke( - adminUser, - 'UpdateAccessControlPolicy', - accessControl, - ...helperInvokeArgs - ) - } - try { - await helperInvoke( - adminUser, - 'CreateVerificationPolicy', - verificationPolicy, - ...helperInvokeArgs - ) - } catch (e) { - logger.info('CreateVerificationPolicy attempting Update') - await helperInvoke( - adminUser, - 'UpdateVerificationPolicy', - verificationPolicy, - ...helperInvokeArgs - ) - } - if (iinAgent || !targetNetwork.startsWith('network')) { - const membership = Buffer.from(fs.readFileSync(membershipPath)).toString() - const memberRecordingUser = iinAgent ? 'iinagent': adminUser // HACK until we add IIN Agents for Corda networks - try { - await helperInvoke(memberRecordingUser, 'CreateMembership', membership, ...helperInvokeArgs) - } catch (e) { - logger.info('CreateMembership attempting Update') - await helperInvoke(memberRecordingUser, 'UpdateMembership', membership, ...helperInvokeArgs) - } - } -} - -export { configureNetworkHelper, configureNetwork } diff --git a/weaver/core/drivers/fabric-driver/server/helpers/logger.ts b/weaver/core/drivers/fabric-driver/server/helpers/logger.ts deleted file mode 100644 index 7b14c5a377..0000000000 --- a/weaver/core/drivers/fabric-driver/server/helpers/logger.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as winston from 'winston' -import * as path from 'path' -const { format, transports } = winston - -const logFormat = format.printf( - info => `${info.timestamp} ${info.level} [${info.label}]: ${info.message}` -) - -const logger = winston.createLogger({ - format: format.combine( - format.label({ label: path.basename(process.mainModule.filename) }), - format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), - format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] }) - ), - transports: [ - new transports.Console({ - format: format.combine(format.colorize(), logFormat) - }) - ], - exitOnError: false -}) - -export default logger diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index a1c6c6ca1c..f19d2cc72b 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -4,12 +4,12 @@ import driverPb from '@hyperledger/cacti-weaver-protos-js/driver/driver_pb'; import logger from './logger'; import { credentials } from '@grpc/grpc-js'; -import { getNetworkConfig } from './helpers/helpers' +import { getNetworkConfig } from '../../../../samples/fabric/fabric-cli/src/helpers/helpers' import { SatpAssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' import fs from 'fs'; import path from 'path'; -import { fabricHelper } from './helpers/fabric-functions'; +import { fabricHelper } from '../../../../samples/fabric/fabric-cli/src/helpers/fabric-functions'; const DB_NAME: string = "driverdb"; const DRIVER_ERROR_CONSTANTS = JSON.parse( diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index dca4221d65..790b4d4759 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -37,8 +37,8 @@ futures = { version = "0.3.27" } base64 = "0.20.0" reqwest = { version = "0.11.16", features = ["json"] } serde_json = "1.0.95" -# cacti_weaver_protos_rs = "2.0.0-alpha.1" cacti_weaver_protos_rs = { path = "../../common/protos-rs/pkg" } +# cacti_weaver_protos_rs = "2.0.0-alpha.1" colored = {version="2.0.4"} rusqlite = "0.29.0" chrono = "0.4" diff --git a/weaver/core/relay/docs/README.md b/weaver/core/relay/docs/README.md index e516fbcbb5..16d1cd2127 100644 --- a/weaver/core/relay/docs/README.md +++ b/weaver/core/relay/docs/README.md @@ -49,7 +49,7 @@ In a new terminal, run the following commands: $ cd weaver/core/drivers/fabric-driver $ cat .env -CONNECTION_PROFILE=/home/user/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json +CONNECTION_PROFILE=/home/user/cacti/weaver/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.json RELAY_ENDPOINT=localhost:9085 RELAY_TLS=false RELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay @@ -104,7 +104,7 @@ $ cat config.json { "network1": { - "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json", + "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.json", "relayEndpoint": "localhost:9080", "mspId": "Org1MSP", "channelName": "mychannel", @@ -112,7 +112,7 @@ $ cat config.json "aclPolicyPrincipalType": "ca" }, "network2": { - "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json", + "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.json", "relayEndpoint": "localhost:9083", "mspId": "Org1MSP", "channelName": "mychannel", @@ -153,10 +153,3 @@ $ cargo run --bin satp_client "9085" "localhost:9085/Dummy_Network/abc:abc:abc:a You should noticed that the messages started to be exchanged between the two gateways. The logs can be seen in the corresponding terminals. - -## Run the gateway unit tests -``` -$ cd weaver/core/relay -$ cargo test --bin server - -``` \ No newline at end of file From b890ffca7bebb453dac74ecc4e083ccb78019fff Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Wed, 22 Nov 2023 09:35:39 +0000 Subject: [PATCH 56/59] feat: initial rfcs for satp --- weaver/rfcs/formats/assets/satp.md | 237 ++++++++++++++++++ .../rfcs/models/infrastructure/relay_satp.md | 91 +++++++ .../protocols/satp/asset-transfer/corda.md | 1 + .../protocols/satp/asset-transfer/fabric.md | 27 ++ .../protocols/satp/asset-transfer/generic.md | 59 +++++ 5 files changed, 415 insertions(+) create mode 100644 weaver/rfcs/formats/assets/satp.md create mode 100644 weaver/rfcs/models/infrastructure/relay_satp.md create mode 100644 weaver/rfcs/protocols/satp/asset-transfer/corda.md create mode 100644 weaver/rfcs/protocols/satp/asset-transfer/fabric.md create mode 100644 weaver/rfcs/protocols/satp/asset-transfer/generic.md diff --git a/weaver/rfcs/formats/assets/satp.md b/weaver/rfcs/formats/assets/satp.md new file mode 100644 index 0000000000..fd1266228b --- /dev/null +++ b/weaver/rfcs/formats/assets/satp.md @@ -0,0 +1,237 @@ + +# Secure Asset Transfer (SAT) + +- RFC: +- Authors: Zakwan Jaroucheh, Venkatraman Ramakrishna, Sandeep Nishad, Rafael Belchior +- Status: Proposed +- Since: + +## Summary +This document specifies the data formats used in the [secure asset transfer protocol (SATP)](../../protocols/satp/asset-transfer/generic.md). The structures defined in this document are generic and the operations on them are generic (see the protocol specification for details.) These structures are oblivious to the specifications and semantics of any digital asset maintained by any DLT application (e.g., any application chaincode in Fabric or any CorDapp in Corda). + +## Transfer Initiation Claims negotiations (Stage-1) + +The purpose of this stage is for the sender gateway (G1) and the receiver gateway (G2) to agree on the asset instance to be transferred from the origin network NW1 to the destination network NW2. In addition, the gateways must exchange validated information or artifacts regarding the originator and beneficiary of the asset transfer, and exchange gateway-specific and network-specific parameters. + +These artifacts are contained in the Transfer Initiation Claims set that is sent from gateway G1 to G2. The set of claims may be negotiated between GH1 and G2 in multi-round set of messages. The first message (Transfer Proposal Claims) maybe multi-round in the sense there is a negotiation of the claims between G1 and G2. G1 sends the signed Transfer Initialization Claim to G2: + +```protobuf +message TransferProposalClaimsRequest { + string message_type = 1; + string asset_asset_id = 2; + string asset_profile_id = 3; + string verified_originator_entity_id = 4; + string verified_beneficiary_entity_id = 5; + string originator_pubkey = 6; + string beneficiary_pubkey = 7; + string sender_gateway_network_id = 8; + string recipient_gateway_network_id = 9; + string client_identity_pubkey = 10; + string server_identity_pubkey = 11; + string sender_gateway_owner_id = 12; + string receiver_gateway_owner_id = 13; +} +``` + +G2 accepts by signing Receipt containing hash of the TransferProposalClaimsRequest: + +```protobuf +message TransferProposalReceiptRequest { + string message_type = 1; + string asset_asset_id = 2; + string asset_profile_id = 3; + string verified_originator_entity_id = 4; + string verified_beneficiary_entity_id = 5; + string originator_pubkey = 6; + string beneficiary_pubkey = 7; + string sender_gateway_network_id = 8; + string recipient_gateway_network_id = 9; + string client_identity_pubkey = 10; + string server_identity_pubkey = 11; + string sender_gateway_owner_id = 12; + string receiver_gateway_owner_id = 13; +} +``` + +G1 chooses and opens a new session (SESSION_ID): +```protobuf +message TransferCommenceRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_transfer_init_claims = 6; + string hash_prev_message = 7; + string client_transfer_number = 8; + string client_signature = 9; +} +``` + +G2 agree to proceed (using the SESSION_ID): +```protobuf +message AckCommenceRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_prev_message = 6; + string server_transfer_number = 7; + string server_signature = 8; +} +``` + + +## Asset Lock Assertion and Receipt (Stage 2) + +In this stage, gateway G1 must issue a signed assertion that the asset in origin network NW1 has been immobilized and under the control of G1. + +G1 lock/escrow asset (2.1): Gateway G1 proceeds to establish a lock or escrow the asset belonging to the originator. This prevents other local transactions in NW1 from changing the state of the asset until such time the lock by G1 is finalized or released. A time-lock or escrow may also be employed: + +```protobuf +message PerformLockRequest { + string session_id = 1; +} +``` + +Lock Assertion (2.2): Gateway G1 sends a digitally signed assertion regarding the locked (escrowed or immobilized) state on the asset in network NW1. The signature by G1 is performed using its entity public-key pair. This signature signifies that G1 (i.e. its owner/operator) is legally standing behind its statement regarding the locked/escrowed state on the asset. The mechanism to lock or immobilize the asset is outside the scope of SATP: + +```protobuf +message LockAssertionRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string lock_assertion_claim = 6; + string lock_assertion_claim_format = 7; + string lock_assertion_expiration = 8; + string hash_prev_message = 9; + string client_transfer_number = 10; + string client_signature = 11; +} +``` + +G2 Logs and Broadcasts lock-assertion information (2.3): Gateway G2 logs a copy of the signed lock-assertion message received in Step 2.4 to its local state data DB2. G2 may also broadcast the fasts of the lock-assertion to all members of network NW2. The mechanism to log and to broadcast is out of scope for SATP: + +```protobuf +message LockAssertionBroadcastRequest { +} +``` + +Lock-Assertion Receipt (2.4): If gateway G2 accepts the signed assertion from G1, then G2 responds with a digitally signed receipt message which includes a hash of the previous lock-assertion message. The signature by G2 is performed using its entity public-key pair. Otherwise, if G2 declines accepting the assertion then G2 can simply ignore the transfer and let the session time-out (i.e. transfer attempt has failed): + +```protobuf +message LockAssertionReceiptRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; + string client_identity_pubkey = 4; + string server_identity_pubkey = 5; + string hash_prev_message = 6; + string server_transfer_number = 7; + string server_signature = 8; +} +``` + +## Commitment Preparation and Finalization (Stage 3) + +In Stage 3 the gateways G1 and G2 finalizes to the asset transfer by performing a commitment protocol (e.g. 2PC or 3PC) as a process (sub-protocol) embedded within the overall SATP asset transfer protocol. + +Commit-prepare (3.1): Gateway G1 indicates to G2 to prepare for the commitment of the transfer. This message must include a hash of the previous messages (message 2.5 and 2.6): + +```protobuf +message CommitPrepareRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} +``` + +Temporary asset mint (3.2): Gateway G2 creates (mints) an equivalent asset in NW2 assigned to itself as the owner. This step can be reversed (i.e. asset destroyed) in the case of the failure in the commitment steps because G2 is still the owner of the asset in NW2: + +```protobuf +message CreateAssetRequest { + string session_id = 1; +} +``` + +Commit-ready (3.3): Gateway G2 sends a commit-ready message to G1 indicating that it is ready to carry-out the last steps of the commitment subprotocol. Note that that the entire asset transfer session can be aborted before this step without affecting the asset state in the respective networks: + +```protobuf +message CommitReadyRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} +``` + +Asset burn (3.4): Gateway G1 extinguishes (burns) the asset in network NW1 which it has locked since Step 2.3: + +```protobuf +message ExtinguishRequest { + string session_id = 1; +} +``` + +Commit-final assertion (3.5): Gateway G1 indicates to G2 that G1 has performed the extinguishment of the asset in NW1. This message must be digitally signed by G1: + +```protobuf +message CommitFinalAssertionRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} +``` + +Asset-assignment (3.6): Gateway G2 assigns the minted asset (which it has been self-holding since Step 3.2) to the Beneficiary: + +```protobuf +message AssignAssetRequest { + string session_id = 1; +} +``` + +ACK-final receipt (3.7): Gateway G2 sends a signed assertion that it has assigned the asset to the intended Beneficiary: + +```protobuf +message AckFinalReceiptRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} +``` + +Receipt broadcast (3.8) Gateway G1 logs a copy of the signed receipt message to its local state data DB2. G1 may also broadcast the fasts of the signed receipt to all members of network NW1. The mechanism to log and to broadcast is out of scope for SATP: + +```protobuf +message AckFinalReceiptBroadcastRequest { +} +``` + +Transfer complete (3.9): Gateway G1 must explicitly close the asset transfer session with gateway G2. This allows both sides to close down the secure channel established earlier in Stage 1: + + +```protobuf +message TransferCompletedRequest { + string message_type = 1; + string session_id = 2; + string transfer_context_id = 3; +} +``` + + + + + + + + + + + diff --git a/weaver/rfcs/models/infrastructure/relay_satp.md b/weaver/rfcs/models/infrastructure/relay_satp.md new file mode 100644 index 0000000000..c5d32c3a84 --- /dev/null +++ b/weaver/rfcs/models/infrastructure/relay_satp.md @@ -0,0 +1,91 @@ + +# Relay Messages + +- RFC: +- Authors: Zakwan Jaroucheh, Venkatraman Ramakrishna, Sandeep Nishad, Rafael Belchior +- Status: Proposed +- Since: + +## Summary + +This document specifies the GRPC services whenever the gateway is involved. + +## SATP Service + +```protobuf +service SATP { + // Stage 1 endpoints + + // The sender gateway sends a TransferProposalClaims request to initiate an asset transfer. + // Depending on the proposal, multiple rounds of communication between the two gateways may happen. + rpc TransferProposalClaims(TransferProposalClaimsRequest) returns (common.ack.Ack) {}; + + // The sender gateway sends a TransferProposalClaims request to signal to the receiver gateway + // that the it is ready to start the transfer of the digital asset + rpc TransferProposalReceipt(TransferProposalReceiptRequest) returns (common.ack.Ack) {}; + + // The sender gateway sends a TransferCommence request to signal to the receiver gateway + // that the it is ready to start the transfer of the digital asset + rpc TransferCommence(TransferCommenceRequest) returns (common.ack.Ack) {}; + + // The receiver gateway sends a AckCommence request to the sender gateway to indicate agreement + // to proceed with the asset transfer + rpc AckCommence(AckCommenceRequest) returns (common.ack.Ack) {}; + + // Stage 2 endpoints + + rpc SendAssetStatus(SendAssetStatusRequest) returns (common.ack.Ack) {}; + + // The sender gateway sends a LockAssertion request to convey a signed claim to the receiver gateway + // declaring that the asset in question has been locked or escrowed by the sender gateway in + // the origin network (e.g. to prevent double spending) + rpc LockAssertion(LockAssertionRequest) returns (common.ack.Ack) {}; + + // The receiver gateway sends a LockAssertionReceipt request to the sender gateway to indicate acceptance + // of the claim(s) delivered by the sender gateway in the previous message + rpc LockAssertionReceipt(LockAssertionReceiptRequest) returns (common.ack.Ack) {}; + + rpc CommitPrepare(CommitPrepareRequest) returns (common.ack.Ack) {}; + + rpc CommitReady(CommitReadyRequest) returns (common.ack.Ack) {}; + + rpc CommitFinalAssertion(CommitFinalAssertionRequest) returns (common.ack.Ack) {}; + + rpc AckFinalReceipt(AckFinalReceiptRequest) returns (common.ack.Ack) {}; + + rpc TransferCompleted(TransferCompletedRequest) returns (common.ack.Ack) {}; +} + +``` + +## Driver Service + +```protobuf +service DriverCommunication { + // As part of SATP, the source reply (sender gateway) sends a PerformLock request to its driver + // to lock a specific asset + rpc PerformLock(PerformLockRequest) returns (common.ack.Ack) {} + + // As part of SATP, the destination reply (receiver gateway) sends a CreateAsset request to its driver + // to create a specific asset + rpc CreateAsset(CreateAssetRequest) returns (common.ack.Ack) {} + + // As part of SATP, the source reply (sender gateway) sends a Extinguish request to its driver + // to extinguish a specific asset + rpc Extinguish(ExtinguishRequest) returns (common.ack.Ack) {} + + // As part of SATP, the destination reply (receiver gateway) sends a AssignAsset request to its driver + // to assign a specific asset + rpc AssignAsset(AssignAssetRequest) returns (common.ack.Ack) {} +} +``` + +## Database + +A gateway should maintain a database to store remote queries and state of the local queries at different stages of the [asset transfer](../../protocols/satp/asset-transfer/generic.md) protocol. Before running the gateway, you need to ensure SQLite (the default database for logs) is installed by following the [database initiaization documentation](../../../../../weaver/core/relay/docs/README.md). + + diff --git a/weaver/rfcs/protocols/satp/asset-transfer/corda.md b/weaver/rfcs/protocols/satp/asset-transfer/corda.md new file mode 100644 index 0000000000..f87f5c14cb --- /dev/null +++ b/weaver/rfcs/protocols/satp/asset-transfer/corda.md @@ -0,0 +1 @@ +# TODO \ No newline at end of file diff --git a/weaver/rfcs/protocols/satp/asset-transfer/fabric.md b/weaver/rfcs/protocols/satp/asset-transfer/fabric.md new file mode 100644 index 0000000000..b9e5b6ad4d --- /dev/null +++ b/weaver/rfcs/protocols/satp/asset-transfer/fabric.md @@ -0,0 +1,27 @@ + +# Asset Transfer Protocol Units in Fabric Networks + +- RFC: +- Authors: Zakwan Jaroucheh, Venkatraman Ramakrishna, Sandeep Nishad, Rafael Belchior +- Status: Proposed +- Since: + +## Summary + +- This document specifies the Hyperledger Fabric implementation of modules, and application adaptation guidelines, for the secure asset transfer protocol. +- Within Weaver, the protocol units to operate on the asset being transferred will be implemented in the Fabric Asset Transfer Chaincode for a Fabric-based network. +- The protocol unit functions are implemented in a library package that can be imported in any chaincode. +- Within Weaver, the SDK will provide user agents (clients) the capability to trigger transfer operations on particular chaincodes maintaining particular digital assets. + +## Fabric Asset Transfer Chaincode + +The following functions should be implemented in a separate package within the Fabric Asset Transfer Chaincode (*Note*: we use Golang syntax here because this chaincode is implemented within Weaver in Golang): + +- `func (s *SmartContract) LockAsset(ctx contractapi.TransactionContextInterface, assetExchangeAgreementSerializedProto64 string, lockInfoSerializedProto64 string) (string, error)`: locks an asset +- `func (s *SmartContract) AssignAsset(ctx contractapi.TransactionContextInterface, assetAgreementSerializedProto64 string, claimInfoSerializedProto64 string) (bool, error)`: changes the ownser of an asset +- `func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, assetType, id string) error` deletes an asset + diff --git a/weaver/rfcs/protocols/satp/asset-transfer/generic.md b/weaver/rfcs/protocols/satp/asset-transfer/generic.md new file mode 100644 index 0000000000..a99d79efbf --- /dev/null +++ b/weaver/rfcs/protocols/satp/asset-transfer/generic.md @@ -0,0 +1,59 @@ + +# Secure Asset Transfer Protocol + +- RFC: +- Authors: Zakwan Jaroucheh, Venkatraman Ramakrishna, Sandeep Nishad, Rafael Belchior +- Status: Proposed +- Since: + +## Summary + +Secure asset transfer protocol in Weaver allows transferring an asset from one network to another. It is implemented by the gateways in the respective +networks. The two gateways implement the protocol in a direct interaction (unmediated). A successful transfer results in the asset being extinguished +(burned) or marked on the origin network, and for the asset to be regenerated (minted) at the destination network. + + +## Protocol Overview + +The secure asset transfer protocol provides a coordination between the two gateways through the various message flows in the protocol that is communicated over a secure channel. The protocol implements a commitment mechanism between the two gateways to ensure that the relevant properties atomicity, consistency, isolation, and durability are achieved in the transfer. + +The mechanism to extinguish (burn) or regenerate (mint) an asset from/into a network by its gateway is dependent on the specific network and is outside the scope of the current architecture. + +In a nutshell, the protocol can be described intuitively as follows: +- **Stage 0**: The two applications utilized by the originator and beneficiary is assumed to interact as part of the asset transfer. In this stage, +the applications App1 and App2 may establish some shared transfer context information (e.g. Context-ID) at the application level that will be made available to their respective gateways G1 and G2. +- **Stage 1**: In this stage gateways G1 and G2 must exchange information (claims) regarding the asset to be transferred, the identity information of the +Originator and Beneficiary and other information regarding relevant actors (e.g. gateway owner/operator). +- **Stage 2**: Gateway G1 must provide gateway G2 with a signed assertion that the asset in NW1 has been immobilized and under the control on G1. +- **Stage 3**: Gateways G1 and G2 commit to the unidirectional asset transfer using a 3PC (3-phase commit) subprotocol. + +## Generic Asset Transfer Flow + +The asset transfer flow is illustrated in more detail in the following figure, and in the description further below. It shows the protocol followed by Alice and Bob, using transaction within the ledgers and cross-network data sharing queries across the ledgers: + + + +## Prerequisites: Smart Contract Developer Responsibilities + +The triggers for each step in the SATP flow must come from the distributed applications pledging and acquiring the asset in question. Because the transfer involves ledger updates, the smart contract portion of the application (e.g., chaincode in Hyperledger Fabric, CorDapp contract in Corda) that processes ledger data through consensus must implement and expose (through its transaction API) several functions. See the [Fabric](./fabric.md) and [Corda](./corda.md) specifications for detailed guidelines when developing applications on those platforms. (*Note*: the function names specified in these pages are suggestive; the developer may pick any suitable names.) + +The application smart contract or distributed application offering these functions must already have mechanisms to: +- Uniquely identify assets and fetch their specifications +- Unambiguously identify the owner(s) of an asset +- Perform lock (or freeze) an asset; i.e., prevent any operations (state or ownership changes) on an asset +- Determine whether an asset is currently in the locked state +- Create an asset and specify the network as the owner +- Assign an asset to an owner by transferring the ownership of the asset from the network to the new owner +- Extinguish an asset by deleting it from the corresponding network + +How the smart contract implements these functions is beyond the purview of Weaver. + +## DLT-Specific Designs + +Implementation of the protocol is DLT-specific. See the following for details on currently supported DLTs: +- [Hyperledger Fabric](./fabric.md) +- [R3 Corda](./corda.md) From fd80261bd28157c930612245d7057639f312af70 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 27 Nov 2023 16:57:29 +0000 Subject: [PATCH 57/59] initial satp github action script --- .../test_weaver-fabric-fabric-satp.yaml | 275 +++----- .../drivers/fabric-driver/.env.satp.template | 25 + weaver/core/relay/Cargo.lock | 616 ++++++++---------- weaver/core/relay/Cargo.toml | 1 + weaver/core/relay/docs/README.md | 2 +- weaver/core/relay/src/main.rs | 4 +- weaver/samples/fabric/satpsimpleasset/go.mod | 2 +- weaver/samples/fabric/satpsimpleasset/go.sum | 8 - 8 files changed, 399 insertions(+), 534 deletions(-) create mode 100644 weaver/core/drivers/fabric-driver/.env.satp.template diff --git a/.github/workflows/test_weaver-fabric-fabric-satp.yaml b/.github/workflows/test_weaver-fabric-fabric-satp.yaml index 8ca1a23b13..5a2c777fae 100644 --- a/.github/workflows/test_weaver-fabric-fabric-satp.yaml +++ b/.github/workflows/test_weaver-fabric-fabric-satp.yaml @@ -4,7 +4,7 @@ # This is a basic workflow to help you get started with Actions -name: Test Asset Transfer +name: Secure Test Asset Transfer # Controls when the workflow will run on: @@ -23,7 +23,7 @@ concurrency: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: - fabric-fabric-asset-transfer-local: + fabric-fabric-satp-local: # if: ${{ false }} # The type of runner that the job will run on runs-on: ubuntu-latest @@ -76,6 +76,11 @@ jobs: go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + # FABRIC NETWORK + - name: Start Fabric Network + run: make start-interop-local CHAINCODE_NAME=satpsimpleasset + working-directory: weaver/tests/network-setups/fabric/dev + # PROTOS - name: Build GO Protos run: | @@ -90,9 +95,9 @@ jobs: make build working-directory: weaver/common/protos-js - - name: Build Java Protos - run: make build - working-directory: weaver/common/protos-java-kt + # - name: Build Java Protos + # run: make build + # working-directory: weaver/common/protos-java-kt # Build Dependencies - name: Build Fabric Interop SDK @@ -111,79 +116,63 @@ jobs: run: make build-local working-directory: weaver/core/drivers/fabric-driver - - name: Build IIN Agent - run: make build-local - working-directory: weaver/core/identity-management/iin-agent - - # FABRIC NETWORK - - - name: Start Fabric Network - run: make start-interop-local CHAINCODE_NAME=simpleassettransfer - working-directory: weaver/tests/network-setups/fabric/dev - - # RELAY - - name: Start Relay for network1 - run: RELAY_CONFIG=config/Fabric_Relay.toml cargo run --bin server &> relay-n1.out & - working-directory: weaver/core/relay + # - name: Build IIN Agent + # run: make build-local + # working-directory: weaver/core/identity-management/iin-agent - - name: Start Relay for network2 - run: RELAY_CONFIG=config/Fabric_Relay2.toml cargo run --bin server &> relay-n2.out & + # GATEWAY + - name: Start Relay for network1 and network2 + run: RELAY_CONFIG=config/Dummy_Relay.toml cargo run --bin server &> gateway.out & working-directory: weaver/core/relay # FABRIC DRIVER - name: Setup Fabric Driver .env run: | - cp .env.template .env - CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json - sed -i "s#path_to_connection_profile#${CCP_PATH}#g" .env - working-directory: weaver/core/drivers/fabric-driver - - - name: Start Fabric Driver for network1 - run: npm run dev &> fdriver-n1.out & + cp .env.satp.template .env working-directory: weaver/core/drivers/fabric-driver - - name: Start Fabric Driver for network2 - run: CONNECTION_PROFILE=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json NETWORK_NAME=network2 RELAY_ENDPOINT=localhost:9083 DRIVER_ENDPOINT=localhost:9095 npm run dev &> fdriver-n2.out & + - name: Start Fabric Driver for network1 and network2 + run: npm run dev &> fdriver.out & working-directory: weaver/core/drivers/fabric-driver # IIN AGENT - - name: Setup Fabric IIN Config - run: | - # FABRIC CONFIG - cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n1.json - CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json - sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n1.json - cat src/fabric-ledger/config-n1.json - cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n2.json - CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json - sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n2.json - cat src/fabric-ledger/config-n2.json - # DNS CONFIG - sed -i "s#iin-agent-Org1MSP-network1#localhost#g" docker-testnet/configs/dnsconfig.json - sed -i "s#iin-agent-Org1MSP-network2#localhost#g" docker-testnet/configs/dnsconfig.json - cat docker-testnet/configs/dnsconfig.json - working-directory: weaver/core/identity-management/iin-agent - - - name: Setup Fabric IIN Env - run: | - cp .env.template .env - sed -i "s##Org1MSP#g" .env - sed -i "s#^DLT_TYPE=.*#DLT_TYPE=fabric#g" .env - sed -i "s##interop#g" .env - sed -i "s#^DNS_CONFIG_PATH=#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig.json#g" .env - sed -i "s#^SECURITY_DOMAIN_CONFIG_PATH=#SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json#g" .env - sed -i "s#^CONFIG_PATH=#CONFIG_PATH=./src/fabric-ledger/config-n1.json#g" .env - sed -i "s#^AUTO_SYNC=#AUTO_SYNC=false#g" .env - cat .env - working-directory: weaver/core/identity-management/iin-agent - - - name: Start Fabric IIN Agent for network1 - run: npm run dev &> iinagent-n1.out & - working-directory: weaver/core/identity-management/iin-agent - - - name: Start Fabric IIN Agent for network2 - run: IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2.json npm run dev &> iinagent-n2.out & - working-directory: weaver/core/identity-management/iin-agent + # - name: Setup Fabric IIN Config + # run: | + # # FABRIC CONFIG + # cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n1.json + # CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json + # sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n1.json + # cat src/fabric-ledger/config-n1.json + # cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n2.json + # CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json + # sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n2.json + # cat src/fabric-ledger/config-n2.json + # # DNS CONFIG + # sed -i "s#iin-agent-Org1MSP-network1#localhost#g" docker-testnet/configs/dnsconfig.json + # sed -i "s#iin-agent-Org1MSP-network2#localhost#g" docker-testnet/configs/dnsconfig.json + # cat docker-testnet/configs/dnsconfig.json + # working-directory: weaver/core/identity-management/iin-agent + + # - name: Setup Fabric IIN Env + # run: | + # cp .env.template .env + # sed -i "s##Org1MSP#g" .env + # sed -i "s#^DLT_TYPE=.*#DLT_TYPE=fabric#g" .env + # sed -i "s##interop#g" .env + # sed -i "s#^DNS_CONFIG_PATH=#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig.json#g" .env + # sed -i "s#^SECURITY_DOMAIN_CONFIG_PATH=#SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json#g" .env + # sed -i "s#^CONFIG_PATH=#CONFIG_PATH=./src/fabric-ledger/config-n1.json#g" .env + # sed -i "s#^AUTO_SYNC=#AUTO_SYNC=false#g" .env + # cat .env + # working-directory: weaver/core/identity-management/iin-agent + + # - name: Start Fabric IIN Agent for network1 + # run: npm run dev &> iinagent-n1.out & + # working-directory: weaver/core/identity-management/iin-agent + + # - name: Start Fabric IIN Agent for network2 + # run: IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2.json npm run dev &> iinagent-n2.out & + # working-directory: weaver/core/identity-management/iin-agent # FABRIC CLI - name: Setup Fabric CLI ENV @@ -193,7 +182,7 @@ jobs: ./bin/fabric-cli env set-file ./.env ./bin/fabric-cli env set MEMBER_CREDENTIAL_FOLDER ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/src/data/credentials ./bin/fabric-cli env set CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/config.json - ./bin/fabric-cli env set DEFAULT_APPLICATION_CHAINCODE simpleassettransfer + ./bin/fabric-cli env set DEFAULT_APPLICATION_CHAINCODE satpsimpleasset ./bin/fabric-cli env set REMOTE_CONFIG_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/remote-network-config.json ./bin/fabric-cli env set CHAINCODE_PATH ${GITHUB_WORKSPACE}/weaver/samples/fabric/fabric-cli/chaincode.json cat .env @@ -206,8 +195,8 @@ jobs: sed -i "s##${GITHUB_WORKSPACE}/weaver#g" config.json ###### Change line number in following commands if config is modified ##### ./bin/fabric-cli config set network2 aclPolicyPrincipalType ca - ./bin/fabric-cli config set network1 chaincode simpleassettransfer - ./bin/fabric-cli config set network2 chaincode simpleassettransfer + ./bin/fabric-cli config set network1 chaincode satpsimpleasset + ./bin/fabric-cli config set network2 chaincode satpsimpleasset cp chaincode.json.template chaincode.json cp remote-network-config.json.template remote-network-config.json working-directory: weaver/samples/fabric/fabric-cli @@ -219,67 +208,33 @@ jobs: ./bin/fabric-cli configure create all --local-network=network2 ./bin/fabric-cli configure network --local-network=network1 ./bin/fabric-cli configure network --local-network=network2 - ./scripts/initAssetsForTransfer.sh + ./scripts/initAsset.sh working-directory: weaver/samples/fabric/fabric-cli - - name: Fabric Sync Membership using IIN Agent - run: | - ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 - sleep 10 - tail -10 ../../../core/identity-management/iin-agent/iinagent-n1.out - ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 - sleep 10 - tail -10 ../../../core/identity-management/iin-agent/iinagent-n2.out - working-directory: weaver/samples/fabric/fabric-cli + # - name: Fabric Sync Membership using IIN Agent + # run: | + # ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 + # sleep 10 + # tail -10 ../../../core/identity-management/iin-agent/iinagent-n1.out + # ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 + # sleep 10 + # tail -10 ../../../core/identity-management/iin-agent/iinagent-n2.out + # working-directory: weaver/samples/fabric/fabric-cli + + # CLIENT + - name: Start the client to initiate the satp protocol + run: cargo run --bin satp_client "9085" "localhost:9085/Dummy_Network/abc:abc:abc:abc" &> client.out & + working-directory: weaver/core/relay # FABRIC CLI - name: Asset Transfer Fabric CLI Non-Fungible Tests run: | COUNT=0 - TOTAL=8 - - # FABRIC2 - FABRIC1 - ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=bond --ref=a03 --data-file=src/data/assetsForTransfer.json &> tmp.out - tail -n 1 tmp.out | grep "Asset pledged with ID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') - - # FABRIC1 - FABRIC2 - ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a03 &> tmp.out - tail -n 1 tmp.out | grep "Called Function ClaimRemoteAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network1 &> tmp.out - tail -n 2 tmp.out | grep "Error: the asset a03 does not exist" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a03"]' --local-network=network2 &> tmp.out - #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a03\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=20 --type=bond --ref=a04 --data-file=src/data/assetsForTransfer.json &> tmp.out - cat tmp.out - - CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') - sleep 20 - - ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a04 &> tmp.out - tail -n 1 tmp.out | grep "cannot claim asset with pledgeId $CID as the expiry time has elapsed" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a04 &> tmp.out - tail -n 1 tmp.out | grep "Called Function ReclaimAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out + TOTAL=1 - ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network1 &> tmp.out - #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer ReadAsset '["bond01","a04"]' --local-network=network2 &> tmp.out - tail -n 2 tmp.out | grep "Error: the asset a04 does not exist" && COUNT=$(( COUNT + 1 )) && echo "PASS" + ./bin/fabric-cli chaincode query --user=bob mychannel satpsimpleasset ReadAsset '["bond01","a0demo"]' --local-network=network2 &> tmp.out + #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a0demo\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a0demo\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out # RESULT @@ -292,76 +247,10 @@ jobs: fi working-directory: weaver/samples/fabric/fabric-cli - # FABRIC CLI - - name: Asset Transfer Fabric CLI Fungible Tests - run: | - COUNT=0 - TOTAL=8 - - # FABRIC2 - FABRIC1 - ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=3600 --type=token --units=50 --owner=alice --data-file=src/data/tokensForTransfer.json &> tmp.out - tail -n 1 tmp.out | grep "Asset pledged with ID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') - - # FABRIC1 - FABRIC2 - ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token.fabric --pledge-id=$CID --param=token1:50 &> tmp.out - tail -n 1 tmp.out | grep "Called Function ClaimRemoteTokenAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer GetMyWallet '[]' --local-network=network1 &> tmp.out - tail -n 2 tmp.out | grep "Result from network query: token1=\"9950\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer GetMyWallet '[]' --local-network=network2 &> tmp.out - tail -n 2 tmp.out | grep "Result from network query: token1=\"50\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli asset transfer pledge --source-network=network1 --dest-network=network2 --recipient=bob --expiry-secs=20 --type=token --units=100 --owner=alice --data-file=src/data/tokensForTransfer.json &> tmp.out - cat tmp.out - - CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //') - sleep 20 - - ./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token.fabric --pledge-id=$CID --param=token1:100 &> tmp.out - tail -n 1 tmp.out | grep "cannot claim asset with pledgeId $CID as the expiry time has elapsed" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=token.fabric --pledge-id=$CID --param=token1:100 &> tmp.out - tail -n 1 tmp.out | grep "Called Function ReclaimTokenAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=alice mychannel simpleassettransfer GetMyWallet '[]' --local-network=network1 &> tmp.out - tail -n 2 tmp.out | grep "Result from network query: token1=\"9950\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - ./bin/fabric-cli chaincode query --user=bob mychannel simpleassettransfer GetMyWallet '[]' --local-network=network2 &> tmp.out - tail -n 2 tmp.out | grep "Result from network query: token1=\"50\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out - - # RESULT - echo "Passed $COUNT/$TOTAL Tests." - - if [ $COUNT == $TOTAL ]; then - exit 0 - else - exit 1 - fi - working-directory: weaver/samples/fabric/fabric-cli - - - name: DEBUG Logs - fabric n1 relay - if: failure() - run: cat weaver/core/relay/relay-n1.out - - - name: DEBUG Logs - fabric n2 relay - if: failure() - run: cat weaver/core/relay/relay-n2.out - - - name: DEBUG Logs - fabric n1 driver + - name: DEBUG Logs - fabric n1 and n2 gateway if: failure() - run: cat weaver/core/drivers/fabric-driver/fdriver-n1.out + run: cat weaver/core/relay/gateway.out - - name: DEBUG Logs - fabric n2 driver + - name: DEBUG Logs - fabric n1 and n2 driver if: failure() - run: cat weaver/core/drivers/fabric-driver/fdriver-n2.out + run: cat weaver/core/drivers/fabric-driver/fdriver.out \ No newline at end of file diff --git a/weaver/core/drivers/fabric-driver/.env.satp.template b/weaver/core/drivers/fabric-driver/.env.satp.template new file mode 100644 index 0000000000..bfaa6bcf17 --- /dev/null +++ b/weaver/core/drivers/fabric-driver/.env.satp.template @@ -0,0 +1,25 @@ +CONNECTION_PROFILE=/home/zakwan/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json +RELAY_ENDPOINT=localhost:9085 +RELAY_TLS=false +RELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay +DRIVER_ENDPOINT=localhost:9090 +DRIVER_TLS=false +DRIVER_TLS_CERT_PATH=path_to_tls_cert_pem_for_driver +DRIVER_TLS_KEY_PATH=path_to_tls_key_pem_for_driver +NETWORK_NAME=network1 +DRIVER_CONFIG= +INTEROP_CHAINCODE=interop +MOCK=false +DB_PATH=driverdbs +#WALLET_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/src/wallet-network1 +WALLET_PATH=/home/zakwan/cacti/weaver/core/drivers/fabric-driver/wallet-network1 +DEBUG=true +LEVELDB_LOCKED_MAX_RETRIES= +LEVELDB_LOCKED_RETRY_BACKOFF_MSEC= +ENABLE_MONITOR=false +MONITOR_SYNC_PERIOD= +MEMBER_CREDENTIAL_FOLDER=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/src/data/credentials +CONFIG_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/config.json +DEFAULT_APPLICATION_CHAINCODE=simpleassettransfer +REMOTE_CONFIG_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/remote-network-config.json +CHAINCODE_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/chaincode.json diff --git a/weaver/core/relay/Cargo.lock b/weaver/core/relay/Cargo.lock index c360b209cd..e3e338c608 100644 --- a/weaver/core/relay/Cargo.lock +++ b/weaver/core/relay/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -31,9 +31,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arrayvec" @@ -90,18 +90,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -112,9 +112,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", @@ -131,7 +131,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustversion", - "serde 1.0.164", + "serde 1.0.193", "sync_wrapper", "tower", "tower-layer", @@ -157,9 +157,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -184,9 +184,9 @@ checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bincode" @@ -194,7 +194,7 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "serde 1.0.164", + "serde 1.0.193", ] [[package]] @@ -205,15 +205,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byteorder" @@ -232,7 +232,7 @@ name = "cacti_weaver_protos_rs" version = "2.0.0-alpha.1" dependencies = [ "prost", - "serde 1.0.164", + "serde 1.0.193", "tonic", ] @@ -260,7 +260,7 @@ dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", - "num-traits 0.2.15", + "num-traits 0.2.17", "wasm-bindgen", "windows-targets", ] @@ -273,7 +273,7 @@ checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ "is-terminal", "lazy_static", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -285,7 +285,7 @@ dependencies = [ "lazy_static", "nom", "rust-ini", - "serde 1.0.164", + "serde 1.0.193", "serde-hjson", "serde_json", "toml", @@ -362,9 +362,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", @@ -381,23 +381,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ - "cc", "libc", + "windows-sys", ] [[package]] @@ -447,9 +436,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -466,9 +455,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -481,9 +470,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -491,15 +480,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -508,38 +497,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -564,9 +553,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -575,15 +564,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -591,7 +580,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -606,9 +595,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "ahash", "allocator-api2", @@ -620,7 +609,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.2", + "hashbrown 0.14.3", ] [[package]] @@ -631,7 +620,13 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "home" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ @@ -640,9 +635,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -695,7 +690,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -729,16 +724,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] @@ -752,9 +747,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -771,30 +766,29 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.12" +name = "indexmap" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ - "cfg-if", + "equivalent", + "hashbrown 0.14.3", ] [[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", + "cfg-if", ] [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" @@ -803,8 +797,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix 0.38.9", - "windows-sys 0.48.0", + "rustix", + "windows-sys", ] [[package]] @@ -824,9 +818,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -852,9 +846,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libsqlite3-sys" @@ -874,15 +868,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "listenfd" @@ -897,9 +885,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -940,22 +928,22 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -999,14 +987,14 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" dependencies = [ - "num-traits 0.2.16", + "num-traits 0.2.17", ] [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -1023,9 +1011,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.4" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] @@ -1038,11 +1026,11 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -1059,7 +1047,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1070,9 +1058,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.93" +version = "0.9.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" dependencies = [ "cc", "libc", @@ -1130,9 +1118,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" @@ -1141,27 +1129,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.2", + "indexmap 2.1.0", ] [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1200,9 +1188,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -1263,9 +1251,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.29" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1333,28 +1321,30 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] -name = "redox_syscall" -version = "0.4.1" +name = "regex" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ - "bitflags 1.3.2", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "regex" -version = "1.8.4" +name = "regex-automata" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" - +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -1363,9 +1353,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "relay" @@ -1378,6 +1368,7 @@ dependencies = [ "colored", "config", "dotenv", + "env_logger", "futures", "lazy_static", "listenfd", @@ -1386,7 +1377,7 @@ dependencies = [ "r2d2_sqlite", "reqwest", "rusqlite", - "serde 1.0.164", + "serde 1.0.193", "serde_json", "sled", "tokio", @@ -1397,11 +1388,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64 0.21.2", + "base64 0.21.5", "bytes", "encoding_rs", "futures-core", @@ -1419,7 +1410,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "serde 1.0.164", + "serde 1.0.193", "serde_json", "serde_urlencoded", "system-configuration", @@ -1442,19 +1433,33 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", - "untrusted", + "spin 0.5.2", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys", +] + [[package]] name = "rusqlite" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -1476,28 +1481,15 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" -dependencies = [ - "bitflags 1.3.2", - "errno", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.9" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.5", - "windows-sys 0.48.0", + "linux-raw-sys", + "windows-sys", ] [[package]] @@ -1507,18 +1499,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" dependencies = [ "log", - "ring", + "ring 0.16.20", "sct", "webpki", ] [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.2", + "base64 0.21.5", ] [[package]] @@ -1559,19 +1551,19 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.5", + "untrusted 0.9.0", ] [[package]] name = "security-framework" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -1582,9 +1574,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -1598,9 +1590,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] @@ -1619,24 +1611,24 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", - "serde 1.0.164", + "serde 1.0.193", ] [[package]] @@ -1648,7 +1640,7 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde 1.0.164", + "serde 1.0.193", ] [[package]] @@ -1678,15 +1670,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -1694,9 +1686,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys", @@ -1708,6 +1700,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1727,9 +1725,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -1765,16 +1763,24 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.6.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ - "autocfg", "cfg-if", "fastrand", - "redox_syscall 0.3.5", - "rustix 0.37.20", - "windows-sys 0.48.0", + "redox_syscall 0.4.1", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", ] [[package]] @@ -1794,20 +1800,19 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374442f06ee49c3a28a8fc9f01a2596fed7559c6b99b31279c3261778e77d84f" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", - "socket2 0.5.4", + "socket2 0.5.5", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1822,13 +1827,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] @@ -1865,9 +1870,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -1883,7 +1888,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "serde 1.0.164", + "serde 1.0.193", ] [[package]] @@ -1967,11 +1972,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1979,20 +1983,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] @@ -2021,9 +2025,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2040,11 +2044,17 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -2053,9 +2063,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.4.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ "getrandom", "rand", @@ -2090,9 +2100,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2100,24 +2110,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -2127,9 +2137,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2137,28 +2147,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -2166,12 +2176,12 @@ dependencies = [ [[package]] name = "webpki" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ecc0cd7cac091bf682ec5efa18b1cff79d617b84181f38b3951dbe135f607f" +checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring", - "untrusted", + "ring 0.17.5", + "untrusted 0.9.0", ] [[package]] @@ -2212,27 +2222,18 @@ dependencies = [ ] [[package]] -name = "windows" -version = "0.48.0" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets", -] +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows-core" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] @@ -2246,18 +2247,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" - +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -2266,84 +2266,42 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - [[package]] name = "winreg" version = "0.50.0" @@ -2365,20 +2323,20 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.20" +version = "0.7.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd66a62464e3ffd4e37bd09950c2b9dd6c4f8767380fabba0d523f9a775bc85a" +checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.20" +version = "0.7.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255c4596d41e6916ced49cfafea18727b24d67878fa180ddfd69b9df34fd1726" +checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.39", ] diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index eaa35b7ca3..dca4221d65 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -47,6 +47,7 @@ log = "0.4.20" r2d2 = "0.8.10" r2d2_sqlite = "0.22.0" lazy_static = "1.4" +env_logger = "0.10.0" [build-dependencies] tonic-build = "0.8.4" \ No newline at end of file diff --git a/weaver/core/relay/docs/README.md b/weaver/core/relay/docs/README.md index 89c8ac49c3..e516fbcbb5 100644 --- a/weaver/core/relay/docs/README.md +++ b/weaver/core/relay/docs/README.md @@ -102,7 +102,7 @@ The Fabric-cli could be used for creating testing assets. Ensure you have the co $ cd weaver/samples/fabric/fabric-cli $ cat config.json -{`` +{ "network1": { "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json", "relayEndpoint": "localhost:9080", diff --git a/weaver/core/relay/src/main.rs b/weaver/core/relay/src/main.rs index df89e22236..0b2caeebdd 100644 --- a/weaver/core/relay/src/main.rs +++ b/weaver/core/relay/src/main.rs @@ -61,8 +61,8 @@ async fn main() -> Result<(), Box> { // Set the RUST_LOG environment variable env::set_var("RUST_LOG", &log_level); - // Initialize the logger - env_logger::init(); + // // Initialize the logger + // env_logger::init(); settings .merge(config::File::with_name(&config_file_name)) diff --git a/weaver/samples/fabric/satpsimpleasset/go.mod b/weaver/samples/fabric/satpsimpleasset/go.mod index a7d64f87cf..eedb9f8ddb 100644 --- a/weaver/samples/fabric/satpsimpleasset/go.mod +++ b/weaver/samples/fabric/satpsimpleasset/go.mod @@ -6,7 +6,7 @@ require ( github.com/golang/protobuf v1.5.3 github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 - github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils v0.0.0-20210920170720-5d5bf2a54081 + github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/libs/testutils v0.0.0-20230907062207-cd6eb2f89fb4 github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a github.com/hyperledger/fabric-contract-api-go v1.2.1 github.com/hyperledger/fabric-protos-go v0.3.0 diff --git a/weaver/samples/fabric/satpsimpleasset/go.sum b/weaver/samples/fabric/satpsimpleasset/go.sum index 23646b5a4f..da4c985ffd 100644 --- a/weaver/samples/fabric/satpsimpleasset/go.sum +++ b/weaver/samples/fabric/satpsimpleasset/go.sum @@ -147,11 +147,3 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha-prerelease h1:MpVTzM8FvQ+2Qij/0DH0cGy2NoC1S5gD5c40HuEQlsI= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha-prerelease/go.mod h1:3DmkYfZoc+TtcAgF3kX6CmQDNKKKCHgbaoQuYu/3ayc= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha-prerelease h1:kks9cM6vS3raV6Ag6FTddFdy11LvUAc6oYHVRUU95ts= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha-prerelease/go.mod h1:jzOMrtkM1AwBUgfedRs7FkcZpl1g/eRe1wnQO9GEoio= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1 h1:r7RknfMWs/riL4saBB31iWfRaP03AJuo19K2ettHP3E= -github.com/hyperledger/cacti/weaver/common/protos-go/v2 v2.0.0-alpha.1/go.mod h1:3DmkYfZoc+TtcAgF3kX6CmQDNKKKCHgbaoQuYu/3ayc= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1 h1:ssYji+cWvfnPYRBQyx7J/aBVTaVdHbb2gOQOLfVZRCw= -github.com/hyperledger/cacti/weaver/core/network/fabric-interop-cc/interfaces/asset-mgmt/v2 v2.0.0-alpha.1/go.mod h1:zei2BRZv+Ln+3o5yr7K900LRpEDCiado8px0hoGuuco= From cb4dbaff21ed763b48428c1fc03b3a79ac8c44cf Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Tue, 28 Nov 2023 07:52:05 +0000 Subject: [PATCH 58/59] corrected the github actions --- .../test_weaver-fabric-fabric-satp.yaml | 84 ++++--------------- .../drivers/fabric-driver/.env.satp.template | 14 ++-- .../fabric-cli/config.satp.template.json | 18 ++++ .../accessControlTemplate_ca.json | 29 +++++++ .../accessControlTemplate_certificate.json | 29 +++++++ .../verificationPolicyTemplate.json | 33 ++++++++ 6 files changed, 130 insertions(+), 77 deletions(-) create mode 100644 weaver/samples/fabric/fabric-cli/config.satp.template.json create mode 100644 weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_ca.json create mode 100644 weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_certificate.json create mode 100644 weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/verificationPolicyTemplate.json diff --git a/.github/workflows/test_weaver-fabric-fabric-satp.yaml b/.github/workflows/test_weaver-fabric-fabric-satp.yaml index 5a2c777fae..a40ca903e5 100644 --- a/.github/workflows/test_weaver-fabric-fabric-satp.yaml +++ b/.github/workflows/test_weaver-fabric-fabric-satp.yaml @@ -2,8 +2,6 @@ # # SPDX-License-Identifier: CC-BY-4.0 -# This is a basic workflow to help you get started with Actions - name: Secure Test Asset Transfer # Controls when the workflow will run @@ -21,18 +19,22 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true -# A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: fabric-fabric-satp-local: # if: ${{ false }} # The type of runner that the job will run on runs-on: ubuntu-latest - # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v3.5.2 + - name: Set up Docker Compose + run: | + curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + sudo chmod +x /usr/local/bin/docker-compose + docker-compose --version + - name: Install Yarn run: npm install -g yarn @@ -81,24 +83,20 @@ jobs: run: make start-interop-local CHAINCODE_NAME=satpsimpleasset working-directory: weaver/tests/network-setups/fabric/dev - # PROTOS + # PROTOS GO - name: Build GO Protos run: | export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" make build working-directory: weaver/common/protos-go - # PROTOS + # PROTOS JS - name: Build JS Protos run: | export PATH="$PATH:${GITHUB_WORKSPACE}/protoc/bin" make build working-directory: weaver/common/protos-js - # - name: Build Java Protos - # run: make build - # working-directory: weaver/common/protos-java-kt - # Build Dependencies - name: Build Fabric Interop SDK run: make build-local @@ -116,10 +114,6 @@ jobs: run: make build-local working-directory: weaver/core/drivers/fabric-driver - # - name: Build IIN Agent - # run: make build-local - # working-directory: weaver/core/identity-management/iin-agent - # GATEWAY - name: Start Relay for network1 and network2 run: RELAY_CONFIG=config/Dummy_Relay.toml cargo run --bin server &> gateway.out & @@ -129,51 +123,13 @@ jobs: - name: Setup Fabric Driver .env run: | cp .env.satp.template .env + sed -i "s##${GITHUB_WORKSPACE}/weaver#g" .env working-directory: weaver/core/drivers/fabric-driver - name: Start Fabric Driver for network1 and network2 run: npm run dev &> fdriver.out & working-directory: weaver/core/drivers/fabric-driver - # IIN AGENT - # - name: Setup Fabric IIN Config - # run: | - # # FABRIC CONFIG - # cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n1.json - # CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json - # sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n1.json - # cat src/fabric-ledger/config-n1.json - # cp src/fabric-ledger/config.json.template src/fabric-ledger/config-n2.json - # CCP_PATH=${GITHUB_WORKSPACE}/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json - # sed -i "s##${CCP_PATH}#g" src/fabric-ledger/config-n2.json - # cat src/fabric-ledger/config-n2.json - # # DNS CONFIG - # sed -i "s#iin-agent-Org1MSP-network1#localhost#g" docker-testnet/configs/dnsconfig.json - # sed -i "s#iin-agent-Org1MSP-network2#localhost#g" docker-testnet/configs/dnsconfig.json - # cat docker-testnet/configs/dnsconfig.json - # working-directory: weaver/core/identity-management/iin-agent - - # - name: Setup Fabric IIN Env - # run: | - # cp .env.template .env - # sed -i "s##Org1MSP#g" .env - # sed -i "s#^DLT_TYPE=.*#DLT_TYPE=fabric#g" .env - # sed -i "s##interop#g" .env - # sed -i "s#^DNS_CONFIG_PATH=#DNS_CONFIG_PATH=./docker-testnet/configs/dnsconfig.json#g" .env - # sed -i "s#^SECURITY_DOMAIN_CONFIG_PATH=#SECURITY_DOMAIN_CONFIG_PATH=./docker-testnet/configs/security-domain-config.json#g" .env - # sed -i "s#^CONFIG_PATH=#CONFIG_PATH=./src/fabric-ledger/config-n1.json#g" .env - # sed -i "s#^AUTO_SYNC=#AUTO_SYNC=false#g" .env - # cat .env - # working-directory: weaver/core/identity-management/iin-agent - - # - name: Start Fabric IIN Agent for network1 - # run: npm run dev &> iinagent-n1.out & - # working-directory: weaver/core/identity-management/iin-agent - - # - name: Start Fabric IIN Agent for network2 - # run: IIN_AGENT_ENDPOINT=localhost:9501 SECURITY_DOMAIN=network2 CONFIG_PATH=./src/fabric-ledger/config-n2.json npm run dev &> iinagent-n2.out & - # working-directory: weaver/core/identity-management/iin-agent - # FABRIC CLI - name: Setup Fabric CLI ENV run: | @@ -191,7 +147,7 @@ jobs: - name: Setup Fabric CLI Config run: | echo ${GITHUB_WORKSPACE} - cp config.template.json config.json + cp config.satp.template.json config.json sed -i "s##${GITHUB_WORKSPACE}/weaver#g" config.json ###### Change line number in following commands if config is modified ##### ./bin/fabric-cli config set network2 aclPolicyPrincipalType ca @@ -201,7 +157,6 @@ jobs: cp remote-network-config.json.template remote-network-config.json working-directory: weaver/samples/fabric/fabric-cli - - name: Fabric CLI Init run: | ./bin/fabric-cli configure create all --local-network=network1 @@ -211,30 +166,19 @@ jobs: ./scripts/initAsset.sh working-directory: weaver/samples/fabric/fabric-cli - # - name: Fabric Sync Membership using IIN Agent - # run: | - # ./bin/fabric-cli configure membership --local-network=network1 --target-network=network2 --iin-agent-endpoint=localhost:9500 - # sleep 10 - # tail -10 ../../../core/identity-management/iin-agent/iinagent-n1.out - # ./bin/fabric-cli configure membership --local-network=network2 --target-network=network1 --iin-agent-endpoint=localhost:9501 - # sleep 10 - # tail -10 ../../../core/identity-management/iin-agent/iinagent-n2.out - # working-directory: weaver/samples/fabric/fabric-cli - # CLIENT - name: Start the client to initiate the satp protocol run: cargo run --bin satp_client "9085" "localhost:9085/Dummy_Network/abc:abc:abc:abc" &> client.out & working-directory: weaver/core/relay - # FABRIC CLI - - name: Asset Transfer Fabric CLI Non-Fungible Tests + # Test SATP + - name: Test SATP run: | COUNT=0 TOTAL=1 - ./bin/fabric-cli chaincode query --user=bob mychannel satpsimpleasset ReadAsset '["bond01","a0demo"]' --local-network=network2 &> tmp.out - #tail -n 1 tmp.out | grep "Result from network query: {\"type\":\"bond01\",\"id\":\"a0demo\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" - cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a0demo\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" + ./bin/fabric-cli chaincode query --user=bob mychannel satpsimpleasset ReadAsset '["bond01","a04"]' --local-network=network1 &> tmp.out + cat tmp.out | tr '\n' ' ' | grep "Result from network query: { \"type\": \"bond01\", \"id\": \"a04\"" && COUNT=$(( COUNT + 1 )) && echo "PASS" cat tmp.out # RESULT diff --git a/weaver/core/drivers/fabric-driver/.env.satp.template b/weaver/core/drivers/fabric-driver/.env.satp.template index bfaa6bcf17..1be61e7341 100644 --- a/weaver/core/drivers/fabric-driver/.env.satp.template +++ b/weaver/core/drivers/fabric-driver/.env.satp.template @@ -1,4 +1,4 @@ -CONNECTION_PROFILE=/home/zakwan/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json +CONNECTION_PROFILE=/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json RELAY_ENDPOINT=localhost:9085 RELAY_TLS=false RELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay @@ -11,15 +11,15 @@ DRIVER_CONFIG= INTEROP_CHAINCODE=interop MOCK=false DB_PATH=driverdbs -#WALLET_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/src/wallet-network1 -WALLET_PATH=/home/zakwan/cacti/weaver/core/drivers/fabric-driver/wallet-network1 +#WALLET_PATH=/samples/fabric/fabric-cli/src/wallet-network1 +WALLET_PATH=/core/drivers/fabric-driver/wallet-network1 DEBUG=true LEVELDB_LOCKED_MAX_RETRIES= LEVELDB_LOCKED_RETRY_BACKOFF_MSEC= ENABLE_MONITOR=false MONITOR_SYNC_PERIOD= -MEMBER_CREDENTIAL_FOLDER=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/src/data/credentials -CONFIG_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/config.json +MEMBER_CREDENTIAL_FOLDER=/samples/fabric/fabric-cli/src/data/credentials +CONFIG_PATH=/samples/fabric/fabric-cli/config.json DEFAULT_APPLICATION_CHAINCODE=simpleassettransfer -REMOTE_CONFIG_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/remote-network-config.json -CHAINCODE_PATH=/home/zakwan/cacti/weaver/samples/fabric/fabric-cli/chaincode.json +REMOTE_CONFIG_PATH=/samples/fabric/fabric-cli/remote-network-config.json +CHAINCODE_PATH=/samples/fabric/fabric-cli/chaincode.json diff --git a/weaver/samples/fabric/fabric-cli/config.satp.template.json b/weaver/samples/fabric/fabric-cli/config.satp.template.json new file mode 100644 index 0000000000..171ab04eb0 --- /dev/null +++ b/weaver/samples/fabric/fabric-cli/config.satp.template.json @@ -0,0 +1,18 @@ +{ + "network1": { + "connProfilePath": "/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json", + "relayEndpoint": "localhost:9080", + "mspId": "Org1MSP", + "channelName": "mychannel", + "chaincode": "satpsimpleasset", + "aclPolicyPrincipalType": "ca" + }, + "network2": { + "connProfilePath": "/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json", + "relayEndpoint": "localhost:9083", + "mspId": "Org1MSP", + "channelName": "mychannel", + "chaincode": "satpsimpleasset", + "aclPolicyPrincipalType": "certificate" + } +} diff --git a/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_ca.json b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_ca.json new file mode 100644 index 0000000000..9d80467610 --- /dev/null +++ b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_ca.json @@ -0,0 +1,29 @@ +{ + "securityDomain": "", + "rules": [ + { + "principal": "", + "principalType": "ca", + "resource": "mychannel:satpsimpleasset:GetHTLCHash:*", + "read": true + }, + { + "principal": "", + "principalType": "ca", + "resource": "mychannel:satpsimpleasset:GetHTLCHashByContractId:*", + "read": true + }, + { + "principal": "", + "principalType": "ca", + "resource": "mychannel:satpsimpleasset:GetHTLCHashPreImage:*", + "read": true + }, + { + "principal": "", + "principalType": "ca", + "resource": "mychannel:satpsimpleasset:GetHTLCHashPreImageByContractId:*", + "read": true + } + ] +} diff --git a/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_certificate.json b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_certificate.json new file mode 100644 index 0000000000..79a86da0f8 --- /dev/null +++ b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/accessControlTemplate_certificate.json @@ -0,0 +1,29 @@ +{ + "securityDomain": "", + "rules": [ + { + "principal": "", + "principalType": "certificate", + "resource": "mychannel:satpsimpleasset:GetHTLCHash:*", + "read": true + }, + { + "principal": "", + "principalType": "certificate", + "resource": "mychannel:satpsimpleasset:GetHTLCHashByContractId:*", + "read": true + }, + { + "principal": "", + "principalType": "certificate", + "resource": "mychannel:satpsimpleasset:GetHTLCHashPreImage:*", + "read": true + }, + { + "principal": "", + "principalType": "certificate", + "resource": "mychannel:satpsimpleasset:GetHTLCHashPreImageByContractId:*", + "read": true + } + ] +} diff --git a/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/verificationPolicyTemplate.json b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/verificationPolicyTemplate.json new file mode 100644 index 0000000000..747b48bd31 --- /dev/null +++ b/weaver/samples/fabric/fabric-cli/src/data/interop/satpsimpleasset/verificationPolicyTemplate.json @@ -0,0 +1,33 @@ +{ + "securityDomain": "", + "identifiers": [ + { + "pattern": "mychannel:satpsimpleasset:GetHTLCHash:*", + "policy": { + "type": "Signature", + "criteria": [] + } + }, + { + "pattern": "mychannel:satpsimpleasset:GetHTLCHashByContractId:*", + "policy": { + "type": "Signature", + "criteria": [] + } + }, + { + "pattern": "mychannel:satpsimpleasset:GetHTLCHashPreImage:*", + "policy": { + "type": "Signature", + "criteria": [] + } + }, + { + "pattern": "mychannel:satpsimpleasset:GetHTLCHashPreImageByContractId:*", + "policy": { + "type": "Signature", + "criteria": [] + } + } + ] +} From 069a96904bdff8239b86717fd633cf7648e500c1 Mon Sep 17 00:00:00 2001 From: outsidethecode Date: Mon, 11 Dec 2023 08:54:39 +0000 Subject: [PATCH 59/59] Corrected the protoc version to be 3.17.3 and rebuild corrected the version of cacti_weaver_protos_rs and added the copyright statement removed the code copied from fabric-cli --- .../protos-go/common/access_control.pb.go | 2 +- weaver/common/protos-go/common/ack.pb.go | 2 +- .../common/protos-go/common/asset_locks.pb.go | 2 +- .../protos-go/common/asset_transfer.pb.go | 2 +- weaver/common/protos-go/common/events.pb.go | 2 +- .../protos-go/common/interop_payload.pb.go | 2 +- .../common/protos-go/common/membership.pb.go | 2 +- weaver/common/protos-go/common/proofs.pb.go | 2 +- weaver/common/protos-go/common/query.pb.go | 2 +- weaver/common/protos-go/common/state.pb.go | 2 +- .../common/verification_policy.pb.go | 2 +- weaver/common/protos-go/corda/view_data.pb.go | 2 +- weaver/common/protos-go/driver/driver.pb.go | 2 +- .../common/protos-go/driver/driver_grpc.pb.go | 2 +- .../common/protos-go/fabric/view_data.pb.go | 2 +- weaver/common/protos-go/identity/agent.pb.go | 2 +- .../protos-go/identity/agent_grpc.pb.go | 2 +- .../common/protos-go/networks/networks.pb.go | 2 +- .../protos-go/networks/networks_grpc.pb.go | 2 +- .../protos-rs/pkg/src/generated/common.ack.rs | 4 + .../pkg/src/generated/common.events.rs | 4 + .../pkg/src/generated/common.query.rs | 4 + .../pkg/src/generated/common.state.rs | 4 + .../pkg/src/generated/driver.driver.rs | 4 + .../pkg/src/generated/networks.networks.rs | 4 + .../pkg/src/generated/relay.asset_transfer.rs | 4 + .../pkg/src/generated/relay.datatransfer.rs | 4 + .../pkg/src/generated/relay.events.rs | 4 + .../protos-rs/pkg/src/generated/relay.satp.rs | 4 + .../server/helpers/fabric-functions.ts | 714 ---------------- .../fabric-driver/server/helpers/helpers.ts | 764 ------------------ .../interop-setup/configure-network.ts | 230 ------ .../fabric-driver/server/helpers/logger.ts | 29 - .../core/drivers/fabric-driver/server/satp.ts | 4 +- weaver/core/relay/Cargo.toml | 2 +- weaver/core/relay/docs/README.md | 13 +- 36 files changed, 65 insertions(+), 1769 deletions(-) delete mode 100644 weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts delete mode 100644 weaver/core/drivers/fabric-driver/server/helpers/helpers.ts delete mode 100644 weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts delete mode 100644 weaver/core/drivers/fabric-driver/server/helpers/logger.ts diff --git a/weaver/common/protos-go/common/access_control.pb.go b/weaver/common/protos-go/common/access_control.pb.go index 266a1c203d..ee04dbca20 100644 --- a/weaver/common/protos-go/common/access_control.pb.go +++ b/weaver/common/protos-go/common/access_control.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/access_control.proto package common diff --git a/weaver/common/protos-go/common/ack.pb.go b/weaver/common/protos-go/common/ack.pb.go index 0b97f2fa93..74d14ab7c6 100644 --- a/weaver/common/protos-go/common/ack.pb.go +++ b/weaver/common/protos-go/common/ack.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/ack.proto package common diff --git a/weaver/common/protos-go/common/asset_locks.pb.go b/weaver/common/protos-go/common/asset_locks.pb.go index d844467dc6..468d81a6da 100644 --- a/weaver/common/protos-go/common/asset_locks.pb.go +++ b/weaver/common/protos-go/common/asset_locks.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/asset_locks.proto package common diff --git a/weaver/common/protos-go/common/asset_transfer.pb.go b/weaver/common/protos-go/common/asset_transfer.pb.go index 1e930e39b0..3f8040a669 100644 --- a/weaver/common/protos-go/common/asset_transfer.pb.go +++ b/weaver/common/protos-go/common/asset_transfer.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/asset_transfer.proto package common diff --git a/weaver/common/protos-go/common/events.pb.go b/weaver/common/protos-go/common/events.pb.go index da4ced1927..4e2bbdd5e8 100644 --- a/weaver/common/protos-go/common/events.pb.go +++ b/weaver/common/protos-go/common/events.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/events.proto package common diff --git a/weaver/common/protos-go/common/interop_payload.pb.go b/weaver/common/protos-go/common/interop_payload.pb.go index 0a1d3c5492..c8593d7e64 100644 --- a/weaver/common/protos-go/common/interop_payload.pb.go +++ b/weaver/common/protos-go/common/interop_payload.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/interop_payload.proto package common diff --git a/weaver/common/protos-go/common/membership.pb.go b/weaver/common/protos-go/common/membership.pb.go index 124f30a1a2..71f48b9700 100644 --- a/weaver/common/protos-go/common/membership.pb.go +++ b/weaver/common/protos-go/common/membership.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/membership.proto package common diff --git a/weaver/common/protos-go/common/proofs.pb.go b/weaver/common/protos-go/common/proofs.pb.go index 5611cd3ee5..cf8964ed0d 100644 --- a/weaver/common/protos-go/common/proofs.pb.go +++ b/weaver/common/protos-go/common/proofs.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/proofs.proto package common diff --git a/weaver/common/protos-go/common/query.pb.go b/weaver/common/protos-go/common/query.pb.go index e66e708342..82753902a5 100644 --- a/weaver/common/protos-go/common/query.pb.go +++ b/weaver/common/protos-go/common/query.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/query.proto package common diff --git a/weaver/common/protos-go/common/state.pb.go b/weaver/common/protos-go/common/state.pb.go index 30d8c72c85..1a56cb19e1 100644 --- a/weaver/common/protos-go/common/state.pb.go +++ b/weaver/common/protos-go/common/state.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/state.proto package common diff --git a/weaver/common/protos-go/common/verification_policy.pb.go b/weaver/common/protos-go/common/verification_policy.pb.go index bbdac635f4..34012c8c03 100644 --- a/weaver/common/protos-go/common/verification_policy.pb.go +++ b/weaver/common/protos-go/common/verification_policy.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: common/verification_policy.proto package common diff --git a/weaver/common/protos-go/corda/view_data.pb.go b/weaver/common/protos-go/corda/view_data.pb.go index 720eca12ac..d334b774b2 100644 --- a/weaver/common/protos-go/corda/view_data.pb.go +++ b/weaver/common/protos-go/corda/view_data.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: corda/view_data.proto package corda diff --git a/weaver/common/protos-go/driver/driver.pb.go b/weaver/common/protos-go/driver/driver.pb.go index 5ed253b931..2bc348cc64 100644 --- a/weaver/common/protos-go/driver/driver.pb.go +++ b/weaver/common/protos-go/driver/driver.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: driver/driver.proto package driver diff --git a/weaver/common/protos-go/driver/driver_grpc.pb.go b/weaver/common/protos-go/driver/driver_grpc.pb.go index ce978ce6f6..d7564b73fa 100644 --- a/weaver/common/protos-go/driver/driver_grpc.pb.go +++ b/weaver/common/protos-go/driver/driver_grpc.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.12.4 +// - protoc v3.17.3 // source: driver/driver.proto package driver diff --git a/weaver/common/protos-go/fabric/view_data.pb.go b/weaver/common/protos-go/fabric/view_data.pb.go index d2320f7369..76a9d5243c 100644 --- a/weaver/common/protos-go/fabric/view_data.pb.go +++ b/weaver/common/protos-go/fabric/view_data.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: fabric/view_data.proto package fabric diff --git a/weaver/common/protos-go/identity/agent.pb.go b/weaver/common/protos-go/identity/agent.pb.go index 2423d1bdb2..242b1cf27d 100644 --- a/weaver/common/protos-go/identity/agent.pb.go +++ b/weaver/common/protos-go/identity/agent.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: identity/agent.proto package identity diff --git a/weaver/common/protos-go/identity/agent_grpc.pb.go b/weaver/common/protos-go/identity/agent_grpc.pb.go index c0f7f20609..af49e8f241 100644 --- a/weaver/common/protos-go/identity/agent_grpc.pb.go +++ b/weaver/common/protos-go/identity/agent_grpc.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.12.4 +// - protoc v3.17.3 // source: identity/agent.proto package identity diff --git a/weaver/common/protos-go/networks/networks.pb.go b/weaver/common/protos-go/networks/networks.pb.go index 9b26730165..377d1b430d 100644 --- a/weaver/common/protos-go/networks/networks.pb.go +++ b/weaver/common/protos-go/networks/networks.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.30.0 -// protoc v3.12.4 +// protoc v3.17.3 // source: networks/networks.proto package networks diff --git a/weaver/common/protos-go/networks/networks_grpc.pb.go b/weaver/common/protos-go/networks/networks_grpc.pb.go index a150a6171b..250b64fcb3 100644 --- a/weaver/common/protos-go/networks/networks_grpc.pb.go +++ b/weaver/common/protos-go/networks/networks_grpc.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.3.0 -// - protoc v3.12.4 +// - protoc v3.17.3 // source: networks/networks.proto package networks diff --git a/weaver/common/protos-rs/pkg/src/generated/common.ack.rs b/weaver/common/protos-rs/pkg/src/generated/common.ack.rs index 08185356b2..c4f738bddc 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.ack.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.ack.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// This message respresents "ACKs" sent between relay-relay, /// relay-driver and relay-network #[derive(serde::Serialize, serde::Deserialize)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.events.rs b/weaver/common/protos-rs/pkg/src/generated/common.events.rs index 745791664b..5d2ffd24ff 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.events.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.events.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.query.rs b/weaver/common/protos-rs/pkg/src/generated/common.query.rs index 870b27fb3f..65ce10d958 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.query.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.query.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// the payload to define the data that is being requested #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos-rs/pkg/src/generated/common.state.rs b/weaver/common/protos-rs/pkg/src/generated/common.state.rs index dbeb44d563..47e28979f4 100644 --- a/weaver/common/protos-rs/pkg/src/generated/common.state.rs +++ b/weaver/common/protos-rs/pkg/src/generated/common.state.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// Metadata for a View #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs index 1a89c27a54..a9b21a94f1 100644 --- a/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs +++ b/weaver/common/protos-rs/pkg/src/generated/driver.driver.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// Data for a View processing by dest-driver #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs index 0e556add31..aefd5c53eb 100644 --- a/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs +++ b/weaver/common/protos-rs/pkg/src/generated/networks.networks.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs b/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs index 9a9d8617b8..3f9d89fdb0 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.asset_transfer.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs b/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs index 21227fde93..a3d738d3f8 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.datatransfer.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// Generated client implementations. pub mod data_transfer_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.events.rs b/weaver/common/protos-rs/pkg/src/generated/relay.events.rs index 50785f0d56..d8f258b622 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.events.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.events.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + /// Generated client implementations. pub mod event_subscribe_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] diff --git a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs index b7147bd954..69b6df5d89 100644 --- a/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs +++ b/weaver/common/protos-rs/pkg/src/generated/relay.satp.rs @@ -1,3 +1,7 @@ +// Copyright IBM Corp. All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 + #[derive(serde::Serialize, serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] diff --git a/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts b/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts deleted file mode 100644 index 08b7597980..0000000000 --- a/weaver/core/drivers/fabric-driver/server/helpers/fabric-functions.ts +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import { Gateway, Wallets, Contract, X509Identity } from 'fabric-network' -import { getNetworkConfig, saveUserCertToFile, handlePromise } from './helpers' -import FabricCAServices from 'fabric-ca-client' -import { Certificate } from '@fidm/x509' -import { Utils, ICryptoKey } from 'fabric-common' -import * as membership_pb from "@hyperledger/cacti-weaver-protos-js/common/membership_pb" -import * as iin_agent_pb from "@hyperledger/cacti-weaver-protos-js/identity/agent_pb" -import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric' -import * as path from 'path' -import * as dotenv from 'dotenv' -dotenv.config({ path: path.resolve(__dirname, '../../.env') }) -import * as fs from 'fs' - -export type InvocationSpec = { - contractName: string - channel: string - args: string[] - ccFunc: string -} - -const getUserCertBase64 = async ( - networkName: string, - username: string -) => { - const wallet = await getWalletForNetwork(networkName) - const userId = await wallet.get(username) - if (!userId) { - throw new Error(`User ${username} not present in wallet of ${networkName}.`) - } - return Buffer.from((userId as X509Identity).credentials.certificate).toString('base64') -} - -const walletSetup = async ( - networkName: string, - ccp: any, - mspId: string, - userName: string, - userPwd: string = '', - isNetworkAdmin: boolean = false, - isIINAgent: boolean = false, - register: boolean = false, - logger: any = console -) => { - // Create a new CA client for interacting with the CA. - const org = ccp.client['organization'] - const caName = ccp.organizations[org]['certificateAuthorities'][0] - const caURL = ccp.certificateAuthorities[caName].url - const ca = new FabricCAServices(caURL) - const ident = ca.newIdentityService() - - const wallet = await getWalletForNetwork(networkName) - - // build a user object for authenticating with the CA - // Check to see if we've already enrolled the admin user. - let adminIdentity = await wallet.get('admin') - - if (adminIdentity) { - logger.debug( - 'An identity for the admin user "admin" already exists in the wallet.' - ) - } else { - // Enroll the admin user, and import the new identity into the wallet. - const enrollment = await ca.enroll({ - enrollmentID: 'admin', - enrollmentSecret: 'adminpw' - }) - const x509Identity = { - credentials: { - certificate: enrollment.certificate, - privateKey: enrollment.key.toBytes() - }, - mspId: mspId, - type: 'X.509' - } - await wallet.put('admin', x509Identity) - adminIdentity = await wallet.get('admin') - } - const provider = wallet.getProviderRegistry().getProvider(adminIdentity.type) - const adminUser = await provider.getUserContext(adminIdentity, 'admin') - const identity = await wallet.get(userName) - logger.debug(`user ${userName}`) - if (!identity) { - // Register the user, enroll the user, and import the new identity into the wallet. - if (!register) { - logger.error(`Identity ${userName} does not exist. Please add user in the network.\n`) - return - } - var secret, enrollment - var enrollmentDone = false - var attributes = [] - if (isNetworkAdmin) { - attributes.push({ "name": "network-admin", "value": "true", "ecert": true }) - } - if (isIINAgent) { - attributes.push({ "name": "iin-agent", "value": "true", "ecert": true }) - } - try { - if (!userPwd) { - secret = await ca.register( - { - affiliation: 'org1.department1', - enrollmentID: userName, - maxEnrollments: -1, - role: 'client', - attrs: attributes - }, - adminUser - ) - } - else { - secret = await ca.register( - { - affiliation: 'org1.department1', - enrollmentID: userName, - enrollmentSecret: userPwd, - maxEnrollments: -1, - role: 'client', - attrs: attributes - }, - adminUser - ) - } - logger.info(`Wallet Setup: Sucessful ${secret}`) - } catch(error) { - const registeredUser = `Identity '${userName}' is already ` - if (!userPwd || !(error.message.includes("Identity ") && error.message.includes(userName) && error.message.includes(" is already registered"))) { - throw new Error(`user ${userName} registration with Fabric CA failed with error: ${error}`) - } else { - try { - enrollment = await ca.enroll({ - enrollmentID: userName, - enrollmentSecret: userPwd - }) - enrollmentDone = true - } catch (error) { - throw new Error(`user ${userName} registration/enrollment with Fabric CA failed with error: ${error}`) - } - } - } - - if (!enrollmentDone) { - enrollment = await ca.enroll({ - enrollmentID: userName, - enrollmentSecret: secret - }) - } - - const x509Identity = { - credentials: { - certificate: enrollment.certificate, - privateKey: enrollment.key.toBytes() - }, - mspId: mspId, - type: 'X.509' - } - await wallet.put(userName, x509Identity) - } - else { - logger.debug(`Identity ${userName} already exists.\n`) - } - - return wallet -} - -const enrollAndRecordWalletIdentity = async ( - userName: string, - userPwd: string, - networkName: string, - isNetworkAdmin: boolean = false, - isIINAgent: boolean = false, - logger: any = console -) => { - const net = getNetworkConfig(networkName) - const ccpPath = path.resolve(__dirname, net.connProfilePath) - const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) - logger.info(net) - - const wallet = await walletSetup(networkName, ccp, net.mspId, userName, userPwd, isNetworkAdmin, isIINAgent, true) - saveUserCertToFile(userName, networkName) - - return wallet -} - -const getCurrentNetworkCredentialPath = (networkName: string): string => { - const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER - ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, networkName) - : path.join(__dirname, '../data', 'credentials', networkName) - return credentialsPath -} - -const getCredentialPath = (): string => { - const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER - ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER) - : path.join(__dirname, '../data', 'credentials') - return credentialsPath -} - -const generateAccessControl = async ( - channel: string, - contractName: string, - connProfilePath: string, - networkName: string, - templatePath: string, - username: string, - mspId = global.__DEFAULT_MSPID__, - logger: any = console -): Promise => { - const { wallet } = await fabricHelper({ - channel, - contractName, - connProfilePath, - networkName, - logger, - mspId - }) - const templateJSON = JSON.parse( - Buffer.from(fs.readFileSync(templatePath)).toString() - ) - const [keyCert, keyCertError] = await handlePromise( - getKeyAndCertForRemoteRequestbyUserName(wallet, username) - ) - if (keyCertError) { - logger.error( - 'Error fetching key and certificate from network', - keyCertError - ) - } - const updatedRules = templateJSON.rules.map(rule => { - if (rule.principalType == 'ca') { - rule.principal = mspId - } else if (rule.principalType == 'certificate') { - rule.principal = keyCert.cert - } else { - logger.error( - 'Error Invalid Principal Type in template file' - ) - } - return rule - }) - const accessControlJSON = { - ...templateJSON, - securityDomain: networkName, - rules: updatedRules - } - logger.debug(`AccessControlJSON ${JSON.stringify(accessControlJSON)}`) - const credentialsPath = getCurrentNetworkCredentialPath(networkName) - fs.writeFileSync( - path.join(credentialsPath, `access-control.json`), - JSON.stringify(accessControlJSON) - ) -} - -const generateVerificationPolicy = async ( - channel, - contractName, - connProfilePath, - networkName: string, - templatePath: string, - mspId = global.__DEFAULT_MSPID__, - logger: any = console -): Promise => { - const templateJSON = JSON.parse( - Buffer.from(fs.readFileSync(templatePath)).toString() - ) - const { gateway } = await fabricHelper({ - channel, - contractName, - connProfilePath, - networkName, - mspId, - logger - }) - - const network = await gateway.getNetwork(channel) - const mspConfig = await getMspConfig(network, logger) - const criteria = Object.keys(formatMSP(mspConfig, networkName).members) - const newIdentifiers = templateJSON.identifiers.map(identifier => { - identifier.policy.criteria = criteria - return identifier - }) - const verificationPolicy = { - ...templateJSON, - identifiers: newIdentifiers, - securityDomain: networkName - } - logger.debug(`VerificationPolicyJSON ${JSON.stringify(verificationPolicy)}`) - const credentialsPath = getCurrentNetworkCredentialPath(networkName) - logger.debug('Credential Path', credentialsPath) - fs.writeFileSync( - path.join(credentialsPath, `verification-policy.json`), - JSON.stringify(verificationPolicy) - ) -} - -const generateMembership = async ( - channel: string, - contractName: string, - connProfilePath: string, - networkName: string, - mspId = global.__DEFAULT_MSPID__, - logger: any = console, - iinAgent: boolean = false -): Promise => { - const { gateway } = await fabricHelper({ - channel, - contractName, - connProfilePath, - networkName, - mspId, - logger - }) - - const network = await gateway.getNetwork(channel) - const mspConfig = await getMspConfig(network, logger) - const membershipJSON = formatMSP(mspConfig, networkName) - const membershipJSONStr = JSON.stringify(membershipJSON) - logger.debug(`membershipJSON: ${membershipJSONStr}`) - - const credentialsPath = getCurrentNetworkCredentialPath(networkName) - logger.debug(`Credentials Path: ${credentialsPath}`) - if (!fs.existsSync(credentialsPath)) { - logger.debug(`Creating directory`) - fs.mkdirSync(credentialsPath, { recursive: true }) - } - - fs.writeFileSync( - path.join(credentialsPath, `membership.json`), - membershipJSONStr - ) - - if (iinAgent) { - // Generate protobufs and attestations for all other networks that have IIN Agents - const credentialFolderPath = getCredentialPath() - const otherNetworkNames = fs - .readdirSync(credentialFolderPath, { withFileTypes: true }) - .filter(dirent => dirent.isDirectory()) - .filter(item => item.name.startsWith('network')) // HACK until we add IIN Agents for Corda networks - .map(item => item.name) - // Reorder the array so that the local network is the first element - // We need to record local membership before recording other networks' memberships - otherNetworkNames.splice(otherNetworkNames.indexOf(networkName), 1) - - if (otherNetworkNames.length > 0) { - // Convert membership object to protobuf - let membershipProto = new membership_pb.Membership() - membershipProto.setSecuritydomain(membershipJSON.securityDomain) - Object.keys(membershipJSON.members).forEach( (memberName, index) => { - const certInfo = membershipJSON.members[memberName] - let memberProto = new membership_pb.Member() - memberProto.setType(certInfo.type) - memberProto.setValue(certInfo.value) - membershipProto.getMembersMap().set(memberName, memberProto) - }) - - // For every other network, generate a counter attested membership set - const serializedMembership = membershipProto.serializeBinary() - const serializedMembershipBase64 = Buffer.from(serializedMembership).toString('base64') - const nonce = 'j849j94j40f440fkfjkld0e043' // Some random string - const membershipBase64WithNonce = serializedMembershipBase64 + nonce - // Get wallet key and cert for this network's IIN Agent - const localWallet = await getWalletForNetwork(networkName) - const localKeyCert = await getKeyAndCertForRemoteRequestbyUserName(localWallet, 'iinagent') - // Sign using wallet identity - let securityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() - securityDomainMember.setSecurityDomain(membershipJSON.securityDomain) - securityDomainMember.setMemberId(Object.keys(membershipJSON.members)[0]) - let localAttestation = new iin_agent_pb.Attestation() - localAttestation.setUnitIdentity(securityDomainMember) - localAttestation.setCertificate(localKeyCert.cert) - const localSig = InteroperableHelper.signMessage(membershipBase64WithNonce, localKeyCert.key.toBytes()) - localAttestation.setSignature(localSig) - localAttestation.setNonce(nonce) - let attestedMembershipSet = new iin_agent_pb.CounterAttestedMembership.AttestedMembershipSet() - attestedMembershipSet.setMembership(serializedMembershipBase64) - attestedMembershipSet.setAttestationsList( [ localAttestation ] ) - const serializedAttestedMembershipSet = attestedMembershipSet.serializeBinary() - const serializedttestedMembershipSetBase64 = Buffer.from(serializedAttestedMembershipSet).toString('base64') - const serializedttestedMembershipSetBase64WithNonce = serializedttestedMembershipSetBase64 + nonce - for (const otherNetworkName of otherNetworkNames) { - // Get wallet key and cert for other network's IIN Agent - const otherWallet = await getWalletForNetwork(otherNetworkName) - const otherKeyCert = await getKeyAndCertForRemoteRequestbyUserName(otherWallet, 'iinagent') - // Sign using wallet identity - let otherSecurityDomainMember = new iin_agent_pb.SecurityDomainMemberIdentity() - otherSecurityDomainMember.setSecurityDomain(otherNetworkName) - otherSecurityDomainMember.setMemberId(getNetworkConfig(otherNetworkName).mspId) - let otherAttestation = new iin_agent_pb.Attestation() - otherAttestation.setUnitIdentity(otherSecurityDomainMember) - otherAttestation.setCertificate(otherKeyCert.cert) - const otherSig = InteroperableHelper.signMessage(serializedttestedMembershipSetBase64WithNonce, otherKeyCert.key.toBytes()) - otherAttestation.setSignature(otherSig) - otherAttestation.setNonce(nonce) - - // Generate chaincode argument and save it in a file - let counterAttestedMembership = new iin_agent_pb.CounterAttestedMembership() - counterAttestedMembership.setAttestedMembershipSet(serializedttestedMembershipSetBase64) - counterAttestedMembership.setAttestationsList( [ otherAttestation ] ) - - fs.writeFileSync( - path.join(credentialsPath, `attested-membership-${otherNetworkName}.proto.serialized`), - Buffer.from(counterAttestedMembership.serializeBinary()).toString('base64') - ) - } - } - } - return membershipJSON -} - -const formatMSP = (mspConfig: MspConfig, networkId: string) => { - const memberObject = { members: {}, securityDomain: networkId } - Object.entries(mspConfig).forEach(([name, value], _) => { - // const cert = Certificate.fromPEM(Buffer.from(value.root_certs[0], 'base64')) - memberObject.members[name] = { - type: 'ca', - value: Buffer.from(value.root_certs[0], 'base64').toString('utf8') - } - }) - return memberObject -} - -type MspConfig = { - [key: string]: { admins: any; root_certs: any; name: string } -} - -const getMspConfig = async ( - network, - logger: any = console -): Promise => { - const mspConfigs = network.channel.getMspids() - const orgMspConfig = {} - logger.debug(mspConfigs) - logger.debug(network.channel.getMsp(mspConfigs[0])) - - mspConfigs.forEach(mspId => { - if (mspId !== 'OrdererMSP') { - logger.info('Getting MSP Info for org with MSP ID: ' + mspId + '.') - const mspConfig = network.getChannel().getMsp(mspId) - delete mspConfig.id - if (Array.isArray(mspConfig.admins)) { - for (let i = 0; i < mspConfig.admins.length; i++) { - mspConfig.admins[i] = Buffer.from(mspConfig.admins[i]).toString( - 'base64' - ) - } - } else if (mspConfig.admins.length === 0) { - mspConfig.admins = [] - } else { - mspConfig.admins = [Buffer.from(mspConfig.admins).toString('base64')] - } - if (Array.isArray(mspConfig.rootCerts)) { - for (let i = 0; i < mspConfig.rootCerts.length; i++) { - mspConfig.rootCerts[i] = Buffer.from(mspConfig.rootCerts[i]).toString( - 'base64' - ) - } - } else if (mspConfig.rootCerts.length === 0) { - mspConfig.rootCerts = [] - } else { - mspConfig.rootCerts = [ - Buffer.from(mspConfig.rootCerts).toString('base64') - ] - } - mspConfig.root_certs = mspConfig.rootCerts - delete mspConfig.rootCerts - if (Array.isArray(mspConfig.intermediateCerts)) { - for (let i = 0; i < mspConfig.intermediateCerts.length; i++) { - mspConfig.intermediateCerts[i] = Buffer.from( - mspConfig.intermediateCerts[i] - ).toString('base64') - } - } else if (mspConfig.intermediateCerts.length === 0) { - mspConfig.intermediateCerts = [] - } else { - mspConfig.intermediateCerts = [ - Buffer.from(mspConfig.intermediateCerts).toString('base64') - ] - } - mspConfig.intermediate_certs = mspConfig.intermediateCerts - delete mspConfig.intermediateCerts - if (Array.isArray(mspConfig.tlsRootCerts)) { - for (let i = 0; i < mspConfig.tlsRootCerts.length; i++) { - mspConfig.tlsRootCerts[i] = Buffer.from( - mspConfig.tlsRootCerts[i] - ).toString('base64') - } - } else if (mspConfig.tlsRootCerts.length === 0) { - mspConfig.tlsRootCerts = [] - } else { - mspConfig.tlsRootCerts = [ - Buffer.from(mspConfig.tlsRootCerts).toString('base64') - ] - } - mspConfig.tls_root_certs = mspConfig.tlsRootCerts - delete mspConfig.tlsRootCerts - if (Array.isArray(mspConfig.tlsIntermediateCerts)) { - for (let i = 0; i < mspConfig.tlsIntermediateCerts.length; i++) { - mspConfig.tlsIntermediateCerts[i] = Buffer.from( - mspConfig.tlsIntermediateCerts[i] - ).toString('base64') - } - } else if (mspConfig.tlsIntermediateCerts.length === 0) { - mspConfig.tlsIntermediateCerts = [] - } else { - mspConfig.tlsIntermediateCerts = [ - Buffer.from(mspConfig.tlsIntermediateCerts).toString('base64') - ] - } - mspConfig.tls_intermediate_certs = mspConfig.tlsIntermediateCerts - delete mspConfig.tlsIntermediateCerts - orgMspConfig[mspId] = mspConfig - } - }) - return orgMspConfig -} - -async function fabricHelper({ - channel, - contractName, - connProfilePath, - networkName, - mspId = global.__DEFAULT_MSPID__, - logger = console, - discoveryEnabled = true, - userString = '', - userPwd = '', - registerUser = true -}: { - channel: string - contractName: string - connProfilePath: string - networkName: string - mspId?: string - discoveryEnabled?: boolean - logger?: any - userString?: string - userPwd?: string - registerUser?: boolean -}): Promise<{ gateway: Gateway; contract: Contract; wallet: any }> { - // load the network configuration - const ccpPath = path.resolve(__dirname, connProfilePath) - const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8')) - // Create a new file system based wallet for managing identities. - // const walletPath = process.env.WALLET_PATH - // ? process.env.WALLET_PATH - // : path.join(__dirname, '../', `wallet-${networkName}`) - - if (!userString) { - userString = `user1` - userPwd = `user1pw` - } - - const wallet = await walletSetup(networkName, ccp, mspId, userString, userPwd, false, false, registerUser, logger) - // Check to see if we've already enrolled the user. - const identity = await wallet.get(userString) - if (!identity) { - logger.info( - `An identity for the user "${userString}" does not exist in the wallet` - ) - logger.info('Run the registerUser.ts application before retrying') - } - // Create a new gateway for connecting to our peer node. - const gateway = new Gateway() - await gateway.connect(ccp, { - wallet, - identity: identity, - discovery: { - enabled: discoveryEnabled, - asLocalhost: process.env.LOCAL === 'false' ? false : true - } - }) - const network = await gateway.getNetwork(channel) - // Get the contract from the network. - const contract = network.getContract(contractName) - return { gateway, contract, wallet } -} - -async function query( - invocationSpec: InvocationSpec, - connProfilePath: string, - networkName: string, - mspId = global.__DEFAULT_MSPID__, - logger: any = console, - userString = '', - registerUser = true -): Promise { - logger.debug('Running invoke on fabric network') - try { - logger.debug( - `QUERY: ${JSON.stringify( - invocationSpec - )} connProfilePath: ${connProfilePath} networkName ${networkName} ` - ) - const { contract, gateway } = await fabricHelper({ - channel: invocationSpec.channel, - contractName: invocationSpec.contractName, - connProfilePath: connProfilePath, - networkName: networkName, - mspId: mspId, - logger: logger, - userString: userString, - registerUser: registerUser - }) - const read = await contract.evaluateTransaction(invocationSpec.ccFunc, ...invocationSpec.args) - const state = Buffer.from(read).toString() - if (state) { - logger.debug(`State From Network:`, state) - } else { - logger.debug(`No State from network`) - } - // Disconnect from the gateway. - await gateway.disconnect() - return state - } catch (error) { - logger.error(`Failed to submit transaction: ${error}`) - throw new Error(error) - } -} - -async function invoke( - invocationSpec: InvocationSpec, - connProfilePath: string, - networkName: string, - mspId = global.__DEFAULT_MSPID__, - logger: any = console, - userString = '', - registerUser = true -): Promise { - logger.debug('Running invoke on fabric network') - try { - const { contract, gateway } = await fabricHelper({ - channel: invocationSpec.channel, - contractName: invocationSpec.contractName, - connProfilePath: connProfilePath, - networkName: networkName, - mspId: mspId, - logger: logger, - userString: userString, - registerUser: registerUser - }) - logger.debug( - `CCFunc: ${invocationSpec.ccFunc} 'CCArgs: ${JSON.stringify(invocationSpec.args)}` - ) - const read = await contract.submitTransaction(invocationSpec.ccFunc, ...invocationSpec.args) - const state = Buffer.from(read).toString() - if (state) { - logger.debug(`Response From Network: ${state}`) - } else { - logger.debug('No Response from network') - } - - // Disconnect from the gateway. - await gateway.disconnect() - return state - } catch (error) { - console.error(`Failed to submit transaction: ${error}`) - throw new Error(error) - } -} - -const getKeyAndCertForRemoteRequestbyUserName = async ( - wallet: any, - username: string -): Promise<{ key: ICryptoKey; cert: any }> => { - if (!wallet) { - throw new Error('No wallet passed') - } - if (!username) { - throw new Error('No username passed') - } - const identity = await wallet.get(username) - if (!identity) { - throw new Error( - 'Identity for username ' + username + ' not present in wallet' - ) - } - // Assume the identity is of type 'fabric-network.X509Identity' - const privKey = Utils.newCryptoSuite().createKeyFromRaw( - identity.credentials.privateKey - ) - return { key: privKey, cert: identity.credentials.certificate } -} - -const getWalletForNetwork = async ( - networkName: string, -) => { - const walletPath = process.env.WALLET_PATH - ? process.env.WALLET_PATH - : path.join(__dirname, '../', `wallet-${networkName}`) - - const wallet = await Wallets.newFileSystemWallet(walletPath) - return wallet -} - - -export { - getUserCertBase64, - walletSetup, - invoke, - query, - enrollAndRecordWalletIdentity, - fabricHelper, - generateMembership, - generateAccessControl, - getKeyAndCertForRemoteRequestbyUserName, - getCredentialPath, - getCurrentNetworkCredentialPath, - generateVerificationPolicy -} diff --git a/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts b/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts deleted file mode 100644 index 624164d8be..0000000000 --- a/weaver/core/drivers/fabric-driver/server/helpers/helpers.ts +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import { getKeyAndCertForRemoteRequestbyUserName, fabricHelper, invoke, query, InvocationSpec } from './fabric-functions' -import { AssetPledge } from "@hyperledger/cacti-weaver-protos-js/common/asset_transfer_pb" -import { InteroperableHelper } from '@hyperledger/cacti-weaver-sdk-fabric' -import * as crypto from 'crypto' -import { promisify } from 'util' -import * as fs from 'fs' -import * as path from 'path' -import * as dotenv from 'dotenv' -import logger from './logger' -dotenv.config({ path: path.resolve(__dirname, '../../.env') }) - - -// UPDATE Following if new env variable or config variable is added. -// Valid keys for .env -const validKeys = [ - 'DEFAULT_CHANNEL', - 'DEFAULT_CHAINCODE', - 'MEMBER_CREDENTIAL_FOLDER', - 'LOCAL', - 'DEFAULT_APPLICATION_CHAINCODE', - 'CONFIG_PATH', - 'REMOTE_CONFIG_PATH', - 'CHAINCODE_PATH' -] -// Valid keys for config -const configKeys = ['connProfilePath', 'relayEndpoint', 'mspId', 'channelName', 'chaincode', 'aclPolicyPrincipalType'] - -const signMessage = (message, privateKey) => { - const sign = crypto.createSign('sha256') - sign.write(message) - sign.end() - return sign.sign(privateKey) -} - -// Basic function to add assets to network, it assumes function is CreateAsset -// TODO: Pass function name as parameter -const addAssets = ({ - dataFilePath, - networkName, - connProfilePath, - invocationSpec, - mspId = global.__DEFAULT_MSPID__, - channelName, - contractName, - ccFunc, - ccType, - logger -}: { - dataFilePath: string - networkName: string - connProfilePath: string - invocationSpec?: InvocationSpec - mspId?: string - channelName?: string - contractName?: string - ccFunc?: string - ccType: string - logger?: any -}): void => { - const filepath = path.resolve(dataFilePath) - const data = JSON.parse(fs.readFileSync(filepath).toString()) - const valuesList = Object.entries(data) - valuesList.forEach(async (item: [string, string]) => { - const currentQuery = invocationSpec - ? invocationSpec - : { - channel: channelName, - contractName: contractName - ? contractName - : 'simpleasset', - ccFunc: '', - args: [] - } - - const { gateway, contract, wallet } = await fabricHelper({ - channel: channelName, - contractName: contractName, - connProfilePath: connProfilePath, - networkName: networkName, - mspId: mspId, - userString: item[1]['owner'], - registerUser: false - }) - const userId = await wallet.get(item[1]['owner']) - const userCert = Buffer.from((userId).credentials.certificate).toString('base64') - - if (ccType == 'bond') { - currentQuery.ccFunc = 'CreateAsset' - currentQuery.args = [...currentQuery.args, item[1]['assetType'], item[1]['id'], userCert, item[1]['issuer'], item[1]['facevalue'], item[1]['maturitydate']] - } else if (ccType == 'token') { - currentQuery.ccFunc = 'IssueTokenAssets' - currentQuery.args = [...currentQuery.args, item[1]['tokenassettype'], item[1]['numunits'], userCert] - } else { - throw new Error(`Unrecognized asset category: ${ccType}`) - } - console.log(currentQuery) - try { - const read = await contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) - const state = Buffer.from(read).toString() - if (state) { - logger.debug(`Response From Network: ${state}`) - } else { - logger.debug('No Response from network') - } - - // Disconnect from the gateway. - await gateway.disconnect() - return state - } catch (error) { - console.error(`Failed to submit transaction: ${error}`) - throw new Error(error) - } - }) -} - - -// Basic function to pledge an asset in one network to another, it assumes function is PledgeAsset -// TODO: Pass function name as parameter -const pledgeAsset = async ({ - dataFilePath, - sourceNetworkName, - destNetworkName, - recipient, - expirySecs, - connProfilePath, - invocationSpec, - mspId = global.__DEFAULT_MSPID__, - channelName, - contractName, - ccFunc, - ccType, - assetOwner, - assetRef, - assetUnits, - logger -}: { - dataFilePath: string - sourceNetworkName: string - destNetworkName: string - recipient: string - expirySecs: number - connProfilePath: string - invocationSpec?: InvocationSpec - mspId?: string - channelName?: string - contractName?: string - ccFunc?: string - ccType: string - assetOwner: string - assetRef: string - assetUnits: number - logger?: any -}): Promise => { - const filepath = path.resolve(dataFilePath) - const data = JSON.parse(fs.readFileSync(filepath).toString()) - let item - if (assetRef) { - item = data[assetRef] - if (!item) { - throw new Error(`Cannot find asset ref ${assetRef} in file ${filepath}`) - } - } else if (assetOwner) { - item = data[assetOwner] - if (!item) { - throw new Error(`Cannot find asset owner ${assetOwner} in file ${filepath}`) - } - } else { - throw new Error(`Neither asset owner nor reference is supplied`) - } - const currentQuery = invocationSpec - ? invocationSpec - : { - channel: channelName, - contractName: contractName - ? contractName - : 'simpleasset', - ccFunc: '', - args: [] - } - - const { gateway, contract, wallet } = await fabricHelper({ - channel: channelName, - contractName: contractName, - connProfilePath: connProfilePath, - networkName: sourceNetworkName, - mspId: mspId, - userString: item['owner'], - registerUser: false - }) - const recipientCert = getUserCertFromFile(recipient, destNetworkName) - const expirationTime = (Math.floor(Date.now()/1000 + expirySecs)).toString() - - if (ccType == 'bond') { - currentQuery.ccFunc = 'PledgeAsset' - currentQuery.args = [...currentQuery.args, item['assetType'], item['id'], destNetworkName, recipientCert, expirationTime] - } else if (ccType == 'token') { - currentQuery.ccFunc = 'PledgeTokenAsset' - currentQuery.args = [...currentQuery.args, item['tokenassettype'], '' + assetUnits, destNetworkName, recipientCert, expirationTime] - } else { - throw new Error(`Unrecognized/unsupported asset category: ${ccType}`) - } - console.log(currentQuery) - try { - const read = await contract.submitTransaction(currentQuery.ccFunc, ...currentQuery.args) - const state = Buffer.from(read).toString() - if (state) { - logger.debug(`Response From Network: ${state}`) - } else { - logger.debug('No Response from network') - } - - // Disconnect from the gateway. - await gateway.disconnect() - return state - } catch (error) { - console.error(`Failed to submit transaction: ${error}`) - throw new Error(error) - } -} - -// Used to obtain remote network user certificate from '${networkId}_UsersAndCerts.json' file. -// This is called during Pledge to get the recipientCert, and during Claim to get the pledgerCert. -const getUserCertFromFile = ( - remoteUser: string, - remoteNetworkId: string -) => { - const usersAndCertsFile = remoteNetworkId + '_UsersAndCerts.json' - const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER - ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, '..') - : path.join(__dirname, '../data', 'credentials', '..') - try { - const dirPath = path.resolve(credentialsPath, 'remoteNetworkUsers') - const filepath = path.resolve(dirPath, usersAndCertsFile) - const usersAndCertsJSON = JSON.parse(fs.readFileSync(filepath).toString()) - logger.debug(`credentialsPath: ${credentialsPath} and usersAndCertsFile: ${usersAndCertsFile}`) - - if (!usersAndCertsJSON[remoteUser]) { - logger.error( - `User: ${remoteUser} does not exist in the file ${usersAndCertsFile}.` - ) - return '' - } - logger.debug(`remoteUser: ${remoteUser} and certificate: ${usersAndCertsJSON[remoteUser]}`) - return usersAndCertsJSON[remoteUser] - } catch (err) { - logger.error(`User: ${remoteUser} does not exist in the file ${usersAndCertsFile}.`) - return '' - } -} - -// Used to store the network user certificate to the file '${networkId}_UsersAndCerts.json'. -// This is used during Pledge to get the recipientCert, and during Claim to get the pledgerCert. -const saveUserCertToFile = ( - remoteUser: string, - remoteNetworkId: string -) => { - const usersAndCertsFile = remoteNetworkId + '_UsersAndCerts.json' - let usersAndCertsJSON = {} - const credentialsPath = process.env.MEMBER_CREDENTIAL_FOLDER - ? path.resolve(__dirname, process.env.MEMBER_CREDENTIAL_FOLDER, '..') - : path.join(__dirname, '../data', 'credentials', '..') - // Don't create the directory 'remoteNetworkUsers' inside 'data/credentials' since each entry there represents - // a network. Instead, create this directory inside 'data' itself. - try { - const dirPath = path.resolve(credentialsPath, 'remoteNetworkUsers') - const filepath = path.resolve(dirPath, usersAndCertsFile) - logger.debug(`credentialsPath: ${credentialsPath} and usersAndCertsFile: ${usersAndCertsFile}`) - - if (!fs.existsSync(dirPath)) { - logger.debug(`Creating directory ${dirPath}`) - fs.mkdirSync(dirPath, { recursive: true }) - } - - if (fs.existsSync(filepath)) { - logger.debug(`Reading contents of the file ${filepath}`) - usersAndCertsJSON = JSON.parse(fs.readFileSync(filepath).toString()) - } - - const remoteUserId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + remoteNetworkId + '/' + remoteUser + '.id').toString()) - const remoteUserCertBase64 = Buffer.from(remoteUserId.credentials.certificate).toString('base64') - - usersAndCertsJSON[remoteUser] = remoteUserCertBase64 - fs.writeFileSync( - path.resolve(filepath), - JSON.stringify(usersAndCertsJSON) - ) - } catch (err) { - logger.error(`User: ${remoteUser} certificate cannot be saved to the file ${usersAndCertsFile}.`) - } -} - -// Basic function to query asset pledge details from a network, it assumes function is GetAssetPledgeStatus -// TODO: Pass function name as parameter -const getAssetPledgeDetails = async ({ - sourceNetworkName, - pledger, - pledgerCert, - destNetworkName, - recipient, - recipientCert, - invocationSpec, - mspId = global.__DEFAULT_MSPID__, - ccFunc, - pledgeId, - logger -}: { - sourceNetworkName: string - pledger: string - pledgerCert: string - destNetworkName: string - recipient: string - recipientCert: string - invocationSpec?: InvocationSpec - mspId?: string - ccFunc?: string - pledgeId: string - logger?: any -}): Promise => { - const netConfig = getNetworkConfig(sourceNetworkName) - - const currentQuery = invocationSpec - ? invocationSpec - : { - channel: netConfig.channelName, - contractName: netConfig.chaincode - ? netConfig.chaincode - : 'simpleasset', - ccFunc: '', - args: [] - } - - const { gateway, contract, wallet } = await fabricHelper({ - channel: netConfig.channelName, - contractName: netConfig.chaincode, - connProfilePath: netConfig.connProfilePath, - networkName: sourceNetworkName, - mspId: netConfig.mspId, - userString: pledger, - registerUser: false - }) - if (!pledgerCert) { - const pledgerId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + sourceNetworkName + '/' + pledger + '.id').toString()) - pledgerCert = Buffer.from(pledgerId.credentials.certificate).toString('base64') - } - if (!recipientCert) { - const recipientId = JSON.parse(fs.readFileSync(__dirname + '/../wallet-' + destNetworkName + '/' + recipient + '.id').toString()) - recipientCert = Buffer.from(recipientId.credentials.certificate).toString('base64') - } - - currentQuery.ccFunc = 'GetAssetPledgeStatus' - currentQuery.args = [...currentQuery.args, pledgeId, pledgerCert, destNetworkName, recipientCert] - console.log(currentQuery) - try { - const read = await contract.evaluateTransaction(currentQuery.ccFunc, ...currentQuery.args) - const state = Buffer.from(read).toString() - if (state) { - logger.debug(`Response From Network: ${state}`) - } else { - logger.debug('No Response from network') - } - - // Disconnect from the gateway. - await gateway.disconnect() - return state - } catch (error) { - console.error(`Failed to submit transaction: ${error}`) - throw new Error(error) - } -} - -// Basic function to query asset pledge details from a network, it assumes function is GetAssetPledgeDetails -// TODO: Pass function name as parameter -const getLocalAssetPledgeDetails = async ({ - sourceNetworkName, - pledgeId, - caller, - ccType, - ccFunc, - logger -}: { - sourceNetworkName: string - pledgeId: string - caller: string - ccType?: string - ccFunc?: string - logger?: any -}): Promise => { - const netConfig = getNetworkConfig(sourceNetworkName) - - const currentQuery = { - channel: netConfig.channelName, - contractName: netConfig.chaincode - ? netConfig.chaincode - : 'simpleasset', - ccFunc: '', - args: [] - } - - if (ccFunc) { - currentQuery.ccFunc = ccFunc - } else if (ccType && ccType == 'token') { - currentQuery.ccFunc = 'GetTokenAssetPledgeDetails' - } else { - currentQuery.ccFunc = 'GetAssetPledgeDetails' - } - currentQuery.args = [...currentQuery.args, pledgeId] - console.log(currentQuery) - try { - const pledgeDetails = await query(currentQuery, - netConfig.connProfilePath, - sourceNetworkName, - netConfig.mspId, - logger, - caller, - false - ) - const pledgeDetailBytes = Buffer.from(pledgeDetails, 'base64') - const pledgeDetailsProto = AssetPledge.deserializeBinary(pledgeDetailBytes) - return pledgeDetailsProto - } catch (error) { - console.error(`Failed to get pledge details: ${error}`) - throw new Error(error) - } -} - -// Basic function to add data to network, it assumes function is Create -// TODO: Pass function name as parameter -const addData = ({ - filename, - networkName, - connProfilePath, - invocationSpec, - mspId = global.__DEFAULT_MSPID__, - logger -}: { - filename: string - networkName: string - connProfilePath: string - invocationSpec?: InvocationSpec - mspId?: string - logger?: any -}): void => { - const filepath = path.resolve(__dirname, '..', 'data', filename) - const data = JSON.parse(fs.readFileSync(filepath).toString()) - const valuesList = Object.entries(data) - valuesList.forEach((item: [string, string]) => { - const currentQuery = invocationSpec - ? invocationSpec - : { - channel: process.env.DEFAULT_CHANNEL - ? process.env.DEFAULT_CHANNEL - : 'mychannel', - contractName: process.env.DEFAULT_APPLICATION_CHAINCODE - ? process.env.DEFAULT_APPLICATION_CHAINCODE - : 'simplestate', - ccFunc: process.env.DEFAULT_APPLICATION_FUNC - ? process.env.DEFAULT_APPLICATION_FUNC - : 'Create', - args: [] - } - currentQuery.args = [...currentQuery.args, item[0], item[1]] - invoke(currentQuery, connProfilePath, networkName, mspId, logger) - }) -} - -// A better way to handle errors for promises -function handlePromise(promise: Promise): Promise<[T?, Error?]> { - const result: Promise<[T?, Error?]> = promise - .then(data => { - const response: [T?, Error?] = [data, undefined] - return response - }) - .catch(error => Promise.resolve([undefined, error])) - return result -} - -// Necessary until gRPC provides a native async friendly solution https://github.com/grpc/grpc-node/issues/54 -function promisifyAll(client): any { - const to = {} - for (const k in client) { - if (typeof client[k] != 'function') continue - to[k] = promisify(client[k].bind(client)) - } - return to -} - -const readJSONFromFile = (jsonfile, logger = console) => { - let data = null - const filepath = path.resolve(jsonfile) - logger.debug('jsonfile is ' + jsonfile) - logger.debug('filepath is ' + filepath) - - try { - const contents = fs.readFileSync(filepath).toString() - logger.debug('contents ' + contents) - data = JSON.parse(contents) - logger.debug('data - ' + JSON.stringify(data)) - } catch (e) { - logger.debug('Error ' + e.message + ' while parsing JSON config file') - throw e - } - return data -} - -// Used for getting network configuration from config.json file. -const getNetworkConfig = ( - networkId: string -): { relayEndpoint?: string; connProfilePath: string; username?: string; mspId?:string; aclPolicyPrincipalType?: string; channelName?: string; chaincode?: string } => { - const configPath = process.env.CONFIG_PATH - ? path.join(process.env.CONFIG_PATH) - : path.join(__dirname, '../../config.json') - try { - const configJSON = JSON.parse(fs.readFileSync(configPath).toString()) - if (!configJSON[networkId]) { - logger.error( - `Network: ${networkId} does not exist in the config.json file` - ) - return { relayEndpoint: '', connProfilePath: '', username: '', mspId: '', aclPolicyPrincipalType: '', channelName: '', chaincode: '' } - } - return configJSON[networkId] - } catch (err) { - logger.error(`Network: ${networkId} does not exist in the config.json file`) - return { relayEndpoint: '', connProfilePath: '', username: '', mspId: '', aclPolicyPrincipalType: '', channelName: '', chaincode: '' } - } -} - -// Used for getting network configuration from config.json file. -const getChaincodeConfig = ( - chaincodeId: string, - chaincodeFunc: string -): { args: Array; replaceIndices: Array } => { - const ccPath = process.env.CHAINCODE_PATH - ? path.join(process.env.CHAINCODE_PATH) - : path.join(__dirname, '../../chaincode.json') - try { - const ccJSON = JSON.parse(fs.readFileSync(ccPath).toString()) - if (!ccJSON[chaincodeId]) { - logger.error( - `Chaincode: ${chaincodeId} does not exist in the chaincode.json file` - ) - return { args: [], replaceIndices: [] } - } - if (!ccJSON[chaincodeId][chaincodeFunc]) { - logger.error( - `Chaincode: ${chaincodeId} does not have a ${chaincodeFunc} function attribute in the chaincode.json file` - ) - return { args: [], replaceIndices: [] } - } - return ccJSON[chaincodeId][chaincodeFunc] - } catch (err) { - logger.error(`Chaincode: ${chaincodeId} does not exist in the chaincode.json file`) - return { args: [], replaceIndices: [] } - } -} - -// Update view address if needed -const generateViewAddress = async ( - viewAddress: string, - sourceNetwork: string, - destNetwork: string, - logger?: any -): Promise => { - if (!viewAddress || viewAddress.length === 0) { - throw new Error('Empty view address') - } - if (viewAddress.indexOf('#') >= 0) { - return viewAddress - } - if (viewAddress.indexOf('GetAssetClaimStatus') >= 0 || viewAddress.indexOf('GetTokenAssetClaimStatus') >= 0) { - // Get asset pledge details - let ccFunc - if (viewAddress.indexOf('GetAssetClaimStatus') >= 0) { - ccFunc = 'GetAssetClaimStatus' - } else { - ccFunc = 'GetTokenAssetClaimStatus' - } - const addressParts = viewAddress.substring(viewAddress.indexOf(ccFunc) + ccFunc.length + 1).split(':') - if (addressParts.length != 6) { - throw new Error(`Expected 6 arguments for ${ccFunc}; found ${addressParts.length}`) - } - if (addressParts[5] != sourceNetwork) { - throw new Error(`Passed source network ID ${sourceNetwork} does not match last chaincode argument in view address ${addressParts[5]}`) - } - const pledgeDetails = await getAssetPledgeDetails({ - sourceNetworkName: addressParts[5], - pledger: '', - pledgerCert: addressParts[4], - destNetworkName: destNetwork, - recipient: '', - recipientCert: addressParts[3], - pledgeId: addressParts[0], - logger: logger - }) - return viewAddress + ':' + deserializeAssetPledge(pledgeDetails).getExpirytimesecs() - } else { - return viewAddress - } -} - -function deserializeAssetPledge(pledgeDetails) { - const pledgeDetailBytes = Buffer.from(pledgeDetails, 'base64') - const pledgeDetailsProto = AssetPledge.deserializeBinary(pledgeDetailBytes) - return pledgeDetailsProto -} - -// Used for creating view address for interop call using remote-network-config.json -const generateViewAddressFromRemoteConfig = ( - networkId: string, - funcName: string, - funcArgs: Array -): any => { - const configPath = process.env.REMOTE_CONFIG_PATH - ? path.join(process.env.REMOTE_CONFIG_PATH) - : path.join(__dirname, '../../remote-network-config.json') - try { - const configJSON = JSON.parse(fs.readFileSync(configPath).toString()) - if (!configJSON[networkId]) { - logger.error( - `Error: ${networkId} does not exist in the remote-network-config.json file` - ) - throw new Error(`Error: ${networkId} does not exist in the remote-network-config.json file`) - } - - const remoteNetConfig = configJSON[networkId] - let address = remoteNetConfig.relayEndpoint + '/' + networkId - if (remoteNetConfig.type == "fabric") { - address = address + '/' + remoteNetConfig.channelName + ':' + - remoteNetConfig.chaincode + ':' + funcName + ':' + funcArgs.join(':') - } else if (remoteNetConfig.type == "corda") { - address = address + '/' + remoteNetConfig.partyEndPoint + '#' + - remoteNetConfig.flowPackage + "." + funcName + ":" + funcArgs.join(':') - } else { - logger.error(`Error: remote network ${remoteNetConfig.type} not supported.`) - throw new Error(`Error: remote network ${remoteNetConfig.type} not supported.`) - } - console.log(`Interop query, funcName: ${funcName} \n funcArgs: ${funcArgs} \n and address: ${address}`) - - return address - } catch (err) { - logger.error(`Error: ${err}`) - throw new Error(err) - } -} - - -// Used for creating view address for interop call using remote-network-config.json -const interopHelper = async ( - networkName: string, - viewAddress: string, - appChaincodeId: string, - applicationFunction: string, - applicationArgs: Array, - replaceIndices: Array, - options: any, // For TLS -): Promise => { - const netConfig = getNetworkConfig(networkName) - if (!netConfig.connProfilePath || !netConfig.channelName || !netConfig.chaincode) { - throw new Error(`No valid config entry found for ${networkName}`) - } - - const { gateway, wallet, contract } = await fabricHelper({ - channel: netConfig.channelName, - contractName: process.env.DEFAULT_CHAINCODE ? process.env.DEFAULT_CHAINCODE : 'interop', - connProfilePath: netConfig.connProfilePath, - networkName, - mspId: netConfig.mspId, - logger, - discoveryEnabled: true, - userString: options['user'] - }) - - const [keyCert, keyCertError] = await handlePromise( - getKeyAndCertForRemoteRequestbyUserName(wallet, options['user']) - ) - if (keyCertError) { - throw new Error(`Error getting key and cert ${keyCertError}`) - } - logger.info(`Starting Interop Query`) - - let relayTlsCAFiles = [] - if (options['relay-tls-ca-files']) { - relayTlsCAFiles = options['relay-tls-ca-files'].split(':') - } - try { - const invokeObject = { - channel: netConfig.channelName, - ccFunc: applicationFunction, - ccArgs: applicationArgs, - contractName: appChaincodeId - } - console.log(invokeObject) - const interopFlowResponse = await InteroperableHelper.interopFlow( - //@ts-ignore this comment can be removed after using published version of interop-sdk - contract, - networkName, - invokeObject, - netConfig.mspId, - netConfig.relayEndpoint, - replaceIndices, - [{ - address: viewAddress, - Sign: true - }], - keyCert, - [], - false, - options['relay-tls'] === 'true', - relayTlsCAFiles, - options['e2e-confidentiality'] === 'true', - gateway - ) - logger.info( - `View from remote network: ${JSON.stringify( - interopFlowResponse.views[0].toObject() - )}. Interop Flow result: ${interopFlowResponse.result || 'successful'}` - ) - logger.debug(`ViewB64: ${Buffer.from(interopFlowResponse.views[0].serializeBinary()).toString('base64')}`) - const remoteValue = (options['e2e-confidentiality'] === 'true' ? - InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0], keyCert.key.toBytes()) : - InteroperableHelper.getResponseDataFromView(interopFlowResponse.views[0]) - ) - if (remoteValue.contents) { - logger.debug(`ViewB64Contents: ${Buffer.from(remoteValue.contents).toString('base64')}`) - } - logger.info( - `Called Function ${applicationFunction}. With Args: ${invokeObject.ccArgs} ${remoteValue.data}` - ) - await gateway.disconnect() - return remoteValue.data - } catch (e) { - logger.error(`Error verifying and storing state`) - logger.error(`Error verifying and storing state: ${e}`) - return "" - } -} - - - -export { - addData, - handlePromise, - promisifyAll, - readJSONFromFile, - signMessage, - getNetworkConfig, - getUserCertFromFile, - saveUserCertToFile, - getChaincodeConfig, - validKeys, - configKeys, - addAssets, - pledgeAsset, - getAssetPledgeDetails, - getLocalAssetPledgeDetails, - generateViewAddress, - generateViewAddressFromRemoteConfig, - interopHelper -} diff --git a/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts b/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts deleted file mode 100644 index b85bbc1db6..0000000000 --- a/weaver/core/drivers/fabric-driver/server/helpers/interop-setup/configure-network.ts +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as fs from 'fs' -import * as path from 'path' -import { - invoke, - getCurrentNetworkCredentialPath, - getCredentialPath, - fabricHelper -} from '../fabric-functions' -import { handlePromise, getNetworkConfig } from '../helpers' -import { MembershipManager } from '@hyperledger/cacti-weaver-sdk-fabric' - -const helperInvoke = async (userId, ccFunc, ccArg, ...args) => { - const [contractName, channelName, connProfilePath, networkName, logger] = args - const [invokeResponse, invokeError] = await handlePromise( - invoke( - { - contractName, - channel: channelName, - ccFunc: ccFunc, - args: [ccArg] - }, - connProfilePath, - networkName, - global.__DEFAULT_MSPID__, - logger, - userId, - (userId === '') - ) - ) - logger.debug(`${ccFunc} Invoke ${JSON.stringify(invokeResponse)}`) - if (invokeError) { - logger.error(`${ccFunc} Invoke Error: ${ccFunc}: ${ccArg}`) - throw new Error(`${ccFunc} Invoke Error ${invokeError}`) - } else { - logger.info(`Successfully invoked ${ccFunc}`) - } -} - -const configureNetwork = async (mainNetwork: string, members: Array = [global.__DEFAULT_MSPID__], logger: any = console, iinAgent: boolean = false) => { - const networkEnv = getNetworkConfig(mainNetwork) - logger.debug(`NetworkEnv: ${JSON.stringify(networkEnv)}`) - if (!networkEnv.relayEndpoint || !networkEnv.connProfilePath) { - logger.error( - 'Please use a valid --local-network. If valid network please check if your environment variables are configured properly' - ) - return - } - - const credentialFolderPath = getCredentialPath() - const networkFolders = fs - .readdirSync(credentialFolderPath, { withFileTypes: true }) - .filter(dirent => dirent.isDirectory()) - .map(item => item.name) - // Reorder the array so that the local network is the first element - // We need to record local membership before recording other networks' memberships - networkFolders.splice(networkFolders.indexOf(mainNetwork), 1) - networkFolders.splice(0, 0, mainNetwork) - - for (const index in networkFolders) { - const network = networkFolders[index] - if (network === mainNetwork) { - // A network needs to load/record only other networks' credentials - await loadLocalHelper( - networkEnv.connProfilePath, - mainNetwork, - process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', - process.env.DEFAULT_CHAINCODE - ? process.env.DEFAULT_CHAINCODE - : 'interop', - members, - logger - ) - continue; - } - const accessControlPath = path.join( - getCurrentNetworkCredentialPath(network), - 'access-control.json' - ) - let membershipPath = "" - if (!network.startsWith('network')) { - membershipPath = path.join( - getCurrentNetworkCredentialPath(network), - 'membership.json' - ) - } else if (iinAgent) { - membershipPath = path.join( - getCurrentNetworkCredentialPath(network), - 'attested-membership-' + mainNetwork + '.proto.serialized' - ) - } - const verificationPolicyPath = path.join( - getCurrentNetworkCredentialPath(network), - 'verification-policy.json' - ) - if ( - !fs.existsSync(accessControlPath) || - !fs.existsSync(verificationPolicyPath) || - (membershipPath !== "" && !fs.existsSync(membershipPath)) - ) { - logger.error(`Missing credential file for network: ${network}`) - } else { - await configureNetworkHelper( - networkEnv.connProfilePath, - mainNetwork, - process.env.DEFAULT_CHANNEL ? process.env.DEFAULT_CHANNEL : 'mychannel', - process.env.DEFAULT_CHAINCODE - ? process.env.DEFAULT_CHAINCODE - : 'interop', - network, - accessControlPath, - membershipPath, - verificationPolicyPath, - logger, - iinAgent - ) - } - } -} - -const loadLocalHelper = async ( - connProfilePath: string, - networkName: string, - channelName: string, - contractName: string, - members: Array, - logger: any = console -): Promise => { - //const localMembership = Buffer.from(fs.readFileSync(localMembershipPath)).toString() - const { gateway } = await fabricHelper({ - channel: channelName, - contractName: contractName, - connProfilePath: connProfilePath, - networkName: networkName, - mspId: global.__DEFAULT_MSPID__, - userString: 'networkadmin', - registerUser: false - }) - try { - const response = await MembershipManager.createLocalMembership(gateway, members, networkName, channelName, contractName) - logger.info('CreateLocalMembership Successful.') - } catch (e) { - logger.error(e) - logger.info('CreateLocalMembership attempting Update') - const response = await MembershipManager.updateLocalMembership(gateway, members, networkName, channelName, contractName) - logger.info('Update Local Memebrship response: success: ', response) - } -} - -const configureNetworkHelper = async ( - connProfilePath: string, - networkName: string, - channelName: string, - contractName: string, - targetNetwork: string, - accessControlPath: string, - membershipPath: string, - verificationPolicyPath: string, - logger: any = console, - iinAgent: boolean = false -): Promise => { - logger.info(`Target Network: ${targetNetwork}`) - const accessControl = Buffer.from( - fs.readFileSync(accessControlPath) - ).toString() - - const verificationPolicy = Buffer.from( - fs.readFileSync(verificationPolicyPath) - ).toString() - - const helperInvokeArgs = [ - contractName, - channelName, - connProfilePath, - networkName, - logger - ] - - const adminUser = 'networkadmin' - - try { - await helperInvoke( - adminUser, - 'CreateAccessControlPolicy', - accessControl, - ...helperInvokeArgs - ) - } catch (e) { - logger.info('CreateAccessControlPolicy attempting Update') - await helperInvoke( - adminUser, - 'UpdateAccessControlPolicy', - accessControl, - ...helperInvokeArgs - ) - } - try { - await helperInvoke( - adminUser, - 'CreateVerificationPolicy', - verificationPolicy, - ...helperInvokeArgs - ) - } catch (e) { - logger.info('CreateVerificationPolicy attempting Update') - await helperInvoke( - adminUser, - 'UpdateVerificationPolicy', - verificationPolicy, - ...helperInvokeArgs - ) - } - if (iinAgent || !targetNetwork.startsWith('network')) { - const membership = Buffer.from(fs.readFileSync(membershipPath)).toString() - const memberRecordingUser = iinAgent ? 'iinagent': adminUser // HACK until we add IIN Agents for Corda networks - try { - await helperInvoke(memberRecordingUser, 'CreateMembership', membership, ...helperInvokeArgs) - } catch (e) { - logger.info('CreateMembership attempting Update') - await helperInvoke(memberRecordingUser, 'UpdateMembership', membership, ...helperInvokeArgs) - } - } -} - -export { configureNetworkHelper, configureNetwork } diff --git a/weaver/core/drivers/fabric-driver/server/helpers/logger.ts b/weaver/core/drivers/fabric-driver/server/helpers/logger.ts deleted file mode 100644 index 7b14c5a377..0000000000 --- a/weaver/core/drivers/fabric-driver/server/helpers/logger.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as winston from 'winston' -import * as path from 'path' -const { format, transports } = winston - -const logFormat = format.printf( - info => `${info.timestamp} ${info.level} [${info.label}]: ${info.message}` -) - -const logger = winston.createLogger({ - format: format.combine( - format.label({ label: path.basename(process.mainModule.filename) }), - format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), - format.metadata({ fillExcept: ['message', 'level', 'timestamp', 'label'] }) - ), - transports: [ - new transports.Console({ - format: format.combine(format.colorize(), logFormat) - }) - ], - exitOnError: false -}) - -export default logger diff --git a/weaver/core/drivers/fabric-driver/server/satp.ts b/weaver/core/drivers/fabric-driver/server/satp.ts index a1c6c6ca1c..f19d2cc72b 100644 --- a/weaver/core/drivers/fabric-driver/server/satp.ts +++ b/weaver/core/drivers/fabric-driver/server/satp.ts @@ -4,12 +4,12 @@ import driverPb from '@hyperledger/cacti-weaver-protos-js/driver/driver_pb'; import logger from './logger'; import { credentials } from '@grpc/grpc-js'; -import { getNetworkConfig } from './helpers/helpers' +import { getNetworkConfig } from '../../../../samples/fabric/fabric-cli/src/helpers/helpers' import { SatpAssetManager, HashFunctions } from '@hyperledger/cacti-weaver-sdk-fabric' import fs from 'fs'; import path from 'path'; -import { fabricHelper } from './helpers/fabric-functions'; +import { fabricHelper } from '../../../../samples/fabric/fabric-cli/src/helpers/fabric-functions'; const DB_NAME: string = "driverdb"; const DRIVER_ERROR_CONSTANTS = JSON.parse( diff --git a/weaver/core/relay/Cargo.toml b/weaver/core/relay/Cargo.toml index dca4221d65..790b4d4759 100644 --- a/weaver/core/relay/Cargo.toml +++ b/weaver/core/relay/Cargo.toml @@ -37,8 +37,8 @@ futures = { version = "0.3.27" } base64 = "0.20.0" reqwest = { version = "0.11.16", features = ["json"] } serde_json = "1.0.95" -# cacti_weaver_protos_rs = "2.0.0-alpha.1" cacti_weaver_protos_rs = { path = "../../common/protos-rs/pkg" } +# cacti_weaver_protos_rs = "2.0.0-alpha.1" colored = {version="2.0.4"} rusqlite = "0.29.0" chrono = "0.4" diff --git a/weaver/core/relay/docs/README.md b/weaver/core/relay/docs/README.md index e516fbcbb5..16d1cd2127 100644 --- a/weaver/core/relay/docs/README.md +++ b/weaver/core/relay/docs/README.md @@ -49,7 +49,7 @@ In a new terminal, run the following commands: $ cd weaver/core/drivers/fabric-driver $ cat .env -CONNECTION_PROFILE=/home/user/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json +CONNECTION_PROFILE=/home/user/cacti/weaver/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.json RELAY_ENDPOINT=localhost:9085 RELAY_TLS=false RELAY_TLSCA_CERT_PATH=path_to_tls_ca_cert_pem_for_relay @@ -104,7 +104,7 @@ $ cat config.json { "network1": { - "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/shared/network1/peerOrganizations/org1.network1.com/connection-org1.json", + "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/network-artifacts/network1/peerOrganizations/org1.network1.com/connection-org1.json", "relayEndpoint": "localhost:9080", "mspId": "Org1MSP", "channelName": "mychannel", @@ -112,7 +112,7 @@ $ cat config.json "aclPolicyPrincipalType": "ca" }, "network2": { - "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/shared/network2/peerOrganizations/org1.network2.com/connection-org1.json", + "connProfilePath": "/home/user/cacti/weaver/tests/network-setups/fabric/network-artifacts/network2/peerOrganizations/org1.network2.com/connection-org1.json", "relayEndpoint": "localhost:9083", "mspId": "Org1MSP", "channelName": "mychannel", @@ -153,10 +153,3 @@ $ cargo run --bin satp_client "9085" "localhost:9085/Dummy_Network/abc:abc:abc:a You should noticed that the messages started to be exchanged between the two gateways. The logs can be seen in the corresponding terminals. - -## Run the gateway unit tests -``` -$ cd weaver/core/relay -$ cargo test --bin server - -``` \ No newline at end of file