diff --git a/.github/workflows/benchmark-machine.yml b/.github/workflows/benchmark-machine.yml index 316cc55261..9ec848368d 100644 --- a/.github/workflows/benchmark-machine.yml +++ b/.github/workflows/benchmark-machine.yml @@ -9,21 +9,27 @@ on: required: true env: - INSTANCE_ID: ${{ secrets.BENCHMARK_INSTANCE_ID }} # remote AWS host to run benchmarking + INSTANCE_ID: ${{ secrets.BENCHMARK_INSTANCE_ID }} BENCHMARK_SSH_USER: ${{ secrets.BENCHMARK_SSH_USER }} - BENCHMARK_SSH_KEYPATH: ${{ secrets.BENCHMARK_SSH_KEYPATH }} + BENCHMARK_SSH_KEY: ${{ secrets.BENCHMARK_SSH_KEY }} jobs: ## run the benchmarking remotely benchmark-machine: - runs-on: jumphost + runs-on: ubuntu-latest steps: - name: Checkout codes on ${{ github.ref }} uses: actions/checkout@v4 with: fetch-depth: 0 - # TODO: maybe use GHA to start/stop remote instance + - name: Set up AWS CLI + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + - name: Start remote instance timeout-minutes: 10 id: start_instance @@ -38,26 +44,30 @@ jobs: break else sleep 20 + SECONDS=$((SECONDS + 20)) fi done echo "Remote instance reachable now after $SECONDS seconds" - remote_ip=`aws ec2 describe-instances --filters 'Name=instance-state-name,Values=running' 'Name=instance-id,Values=${{ env.INSTANCE_ID }}' --query 'Reservations[*].Instances[*].[PublicIpAddress]' --output text` - echo "Running instances ip address: $remote_ip" + remote_ip=$(aws ec2 describe-instances --filters 'Name=instance-state-name,Values=running' 'Name=instance-id,Values=${{ env.INSTANCE_ID }}' --query 'Reservations[*].Instances[*].[PublicIpAddress]' --output text) + echo "Running instances IP address: $remote_ip" echo "remote_ip=$remote_ip" >> $GITHUB_OUTPUT - # exit status should propagate through ssh - name: Remotely benchmark machine timeout-minutes: 10 run: | - echo "Running instances ip address: ${{ steps.start_instance.outputs.remote_ip }}" - ssh -x -o StrictHostKeychecking=no "${{ steps.start_instance.outputs.remote_ip }}" -l ${{ env.BENCHMARK_SSH_USER }} -i ${{ env.BENCHMARK_SSH_KEYPATH }} \ - docker pull litentry/litentry-parachain:${{ github.event.inputs.docker_tag }} && \ - docker run --rm litentry/litentry-parachain:${{ github.event.inputs.docker_tag }} benchmark machine --allow-fail --chain=litmus-dev + echo "Running instance's IP address: ${{ steps.start_instance.outputs.remote_ip }}" + cat << EOF > ./benchmark-server-key.pem + ${{ env.BENCHMARK_SSH_KEY }} + EOF + chmod 600 ./benchmark-server-key.pem + ssh -o StrictHostKeyChecking=no -i ./benchmark-server-key.pem "${{ env.BENCHMARK_SSH_USER }}@${{ steps.start_instance.outputs.remote_ip }}" \ + "docker pull litentry/litentry-parachain:${{ github.event.inputs.docker_tag }} && \ + docker run --rm litentry/litentry-parachain:${{ github.event.inputs.docker_tag }} benchmark machine --allow-fail --chain=litmus-dev" - name: Stop remote instance if: always() run: | aws ec2 stop-instances --instance-ids ${{ env.INSTANCE_ID }} sleep 5 - ret=`aws ec2 describe-instance-status --instance-ids ${{ env.INSTANCE_ID }} | jq '.InstanceStatuses[0].InstanceState.Name'` + ret=$(aws ec2 describe-instance-status --instance-ids ${{ env.INSTANCE_ID }} --query 'InstanceStatuses[0].InstanceState.Name' --output text) echo "Remote instance running state: $ret" diff --git a/.github/workflows/benchmark-runtime-weights.yml b/.github/workflows/benchmark-runtime-weights.yml index 32e3461b8d..a9d6d85f0c 100644 --- a/.github/workflows/benchmark-runtime-weights.yml +++ b/.github/workflows/benchmark-runtime-weights.yml @@ -30,9 +30,9 @@ on: required: true env: - INSTANCE_ID: ${{ secrets.BENCHMARK_INSTANCE_ID }} # remote AWS host to run benchmarking + INSTANCE_ID: ${{ secrets.BENCHMARK_INSTANCE_ID }} BENCHMARK_SSH_USER: ${{ secrets.BENCHMARK_SSH_USER }} - BENCHMARK_SSH_KEYPATH: ${{ secrets.BENCHMARK_SSH_KEYPATH }} + BENCHMARK_SSH_KEY: ${{ secrets.BENCHMARK_SSH_KEY }} DOCKER_BUILDKIT: 1 jobs: @@ -77,7 +77,7 @@ jobs: ## run the benchmarking remotely benchmark: - runs-on: jumphost + runs-on: ubuntu-latest needs: build-docker # see https://github.com/actions/runner/issues/491 if: | @@ -111,25 +111,33 @@ jobs: run: | docker pull litentry/litentry-parachain:runtime-benchmarks + - name: Set up AWS CLI + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: us-east-1 + # TODO: maybe use GHA to start/stop remote instance - name: Start remote instance timeout-minutes: 10 id: start_instance run: | - aws ec2 start-instances --region ap-southeast-1 --instance-ids ${{ env.INSTANCE_ID }} + aws ec2 start-instances --instance-ids ${{ env.INSTANCE_ID }} sleep 5 - instance_status="aws ec2 describe-instance-status --region ap-southeast-1 --instance-ids ${{ env.INSTANCE_ID }} --query 'InstanceStatuses[0].InstanceStatus.Status' --output text" - system_status="aws ec2 describe-instance-status --region ap-southeast-1 --instance-ids ${{ env.INSTANCE_ID }} --query 'InstanceStatuses[0].SystemStatus.Status' --output text" + instance_status="aws ec2 describe-instance-status --instance-ids ${{ env.INSTANCE_ID }} --query 'InstanceStatuses[0].InstanceStatus.Status' --output text" + system_status="aws ec2 describe-instance-status --instance-ids ${{ env.INSTANCE_ID }} --query 'InstanceStatuses[0].SystemStatus.Status' --output text" SECONDS=0 while : ; do if [ "$(eval $instance_status)" = "ok" ] && [ "$(eval $system_status)" = "ok" ]; then break else sleep 20 + SECONDS=$((SECONDS + 20)) fi done echo "Remote instance reachable now after $SECONDS seconds" - remote_ip=`aws ec2 describe-instances --region ap-southeast-1 --filters 'Name=instance-state-name,Values=running' 'Name=instance-id,Values=${{ env.INSTANCE_ID }}' --query 'Reservations[*].Instances[*].[PublicIpAddress]' --output text` + remote_ip=`aws ec2 describe-instances --filters 'Name=instance-state-name,Values=running' 'Name=instance-id,Values=${{ env.INSTANCE_ID }}' --query 'Reservations[*].Instances[*].[PublicIpAddress]' --output text` echo "Running instances ip address: $remote_ip" echo "remote_ip=$remote_ip" >> $GITHUB_OUTPUT @@ -144,10 +152,14 @@ jobs: if [ "$arg" = "*" ]; then arg="\\$arg"; fi + cat << EOF > ./benchmark-server-key.pem + ${{ env.BENCHMARK_SSH_KEY }} + EOF + chmod 600 ./benchmark-server-key.pem for c in $chain; do - ssh -x -o StrictHostKeychecking=no ${{ secrets.BENCHMARK_INSTANCE_IP }} -l ${{ env.BENCHMARK_SSH_USER }} 'bash -s' < scripts/benchmark-weight-remote.sh "$c" "${GITHUB_REF#refs/heads/}" "$arg" + ssh -x -i ./benchmark-server-key.pem -o StrictHostKeychecking=no "${{ steps.start_instance.outputs.remote_ip }}" -l ${{ env.BENCHMARK_SSH_USER }} 'bash -s' < scripts/benchmark-weight-remote.sh "$c" "${GITHUB_REF#refs/heads/}" "$arg" echo "copy generated weights files back ..." - scp -o StrictHostKeychecking=no "${{ env.BENCHMARK_SSH_USER }}"@"${{ secrets.BENCHMARK_INSTANCE_IP }}":/tmp/litentry-parachain/runtime/$c/src/weights/*.rs runtime/$c/src/weights/ + scp -o StrictHostKeychecking=no -i ./benchmark-server-key.pem "${{ env.BENCHMARK_SSH_USER }}"@"${{ steps.start_instance.outputs.remote_ip }}":/tmp/litentry-parachain/runtime/$c/src/weights/*.rs runtime/$c/src/weights/ done echo "======================" git status @@ -155,9 +167,9 @@ jobs: - name: Stop remote instance if: always() run: | - aws ec2 stop-instances --region ap-southeast-1 --instance-ids ${{ env.INSTANCE_ID }} + aws ec2 stop-instances --instance-ids ${{ env.INSTANCE_ID }} sleep 5 - ret=`aws ec2 describe-instance-status --region ap-southeast-1 --instance-ids ${{ env.INSTANCE_ID }} | jq '.InstanceStatuses[0].InstanceState.Name'` + ret=`aws ec2 describe-instance-status --instance-ids ${{ env.INSTANCE_ID }} | jq '.InstanceStatuses[0].InstanceState.Name'` echo "Remote instance running state: $ret" - name: Create auto PR diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bff6366b6d..541847721f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -646,9 +646,10 @@ jobs: - test_name: lit-dr-vc-test - test_name: lit-parentchain-nonce - test_name: lit-test-failed-parentchain-extrinsic - - test_name: lit-scheduled-enclave-test - test_name: lit-twitter-identity-test - test_name: lit-discord-identity-test + - test_name: lit-assertion-contracts-test + steps: - uses: actions/checkout@v4 @@ -732,7 +733,6 @@ jobs: - test_name: lit-di-vc-multiworker-test - test_name: lit-dr-vc-multiworker-test - test_name: lit-resume-worker - - test_name: lit-scheduled-enclave-multiworker-test steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/create-release-draft.yml b/.github/workflows/create-release-draft.yml index 5644e51fa5..b2f7d52183 100644 --- a/.github/workflows/create-release-draft.yml +++ b/.github/workflows/create-release-draft.yml @@ -182,14 +182,17 @@ jobs: # see https://docs.docker.com/build/drivers/ driver: docker + # the key for identity worker enclave shall be renewed when switching to sdk-v2.0.0 - name: Write enclave signing key run: | cat << EOF > tee-worker/enclave_key.pem - ${{ secrets.IDENTITY_ENCLAVE_SIGNING_KEY }} + ${{ secrets.IDENTITY_ENCLAVE_STAGING_SIGNING_KEY }} EOF - name: Build local builder uses: docker/build-push-action@v6 + env: + DOCKER_BUILD_RECORD_UPLOAD: false with: context: . file: tee-worker/build.Dockerfile @@ -205,6 +208,8 @@ jobs: - name: Build worker uses: docker/build-push-action@v6 + env: + DOCKER_BUILD_RECORD_UPLOAD: false with: context: . file: tee-worker/build.Dockerfile @@ -253,11 +258,13 @@ jobs: - name: Write enclave signing key run: | cat << EOF > bitacross-worker/enclave_key.pem - ${{ secrets.BITACROSS_ENCLAVE_SIGNING_KEY }} + ${{ secrets.BITACROSS_ENCLAVE_PROD_SIGNING_KEY }} EOF - name: Build local builder uses: docker/build-push-action@v6 + env: + DOCKER_BUILD_RECORD_UPLOAD: false with: context: . file: bitacross-worker/build.Dockerfile @@ -273,6 +280,8 @@ jobs: - name: Build worker uses: docker/build-push-action@v6 + env: + DOCKER_BUILD_RECORD_UPLOAD: false with: context: . file: bitacross-worker/build.Dockerfile diff --git a/.github/workflows/create-release-issue.yml b/.github/workflows/create-release-issue.yml index 000378b0c5..36665b8c8e 100644 --- a/.github/workflows/create-release-issue.yml +++ b/.github/workflows/create-release-issue.yml @@ -2,9 +2,9 @@ name: Create release issue on: push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+-[0-9]+' - - 'p[0-9]+.[0-9]+.[0-9]+-[0-9]+-w[0-9]+.[0-9]+.[0-9]+-[0-9]+' + - 'disabled-v[0-9]+.[0-9]+.[0-9]+' + - 'disabled-v[0-9]+.[0-9]+.[0-9]+-[0-9]+' + - 'disabled-p[0-9]+.[0-9]+.[0-9]+-[0-9]+-w[0-9]+.[0-9]+.[0-9]+-[0-9]+' jobs: create-release-issue: diff --git a/Cargo.lock b/Cargo.lock index 5a6c3e9e54..2453dafc85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -445,18 +445,18 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -1074,7 +1074,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -1747,7 +1747,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -2046,7 +2046,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -2073,7 +2073,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -2090,7 +2090,7 @@ checksum = "b8fcfa71f66c8563c4fa9dd2bb68368d50267856f831ac5d85367e0805f9606c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -2280,7 +2280,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -2368,7 +2368,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -2561,7 +2561,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -2572,7 +2572,7 @@ checksum = "b893c4eb2dc092c811165f84dc7447fae16fb66521717968c34c509b39b1a5c5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -2872,7 +2872,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -3389,7 +3389,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -3504,7 +3504,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -3516,7 +3516,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -3526,7 +3526,7 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -3693,7 +3693,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -5508,6 +5508,7 @@ dependencies = [ "pallet-aura", "pallet-authorship", "pallet-balances", + "pallet-bitacross", "pallet-bounties", "pallet-bridge", "pallet-bridge-transfer", @@ -5524,6 +5525,7 @@ dependencies = [ "pallet-proxy", "pallet-scheduler", "pallet-session", + "pallet-teebag", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -5565,7 +5567,7 @@ dependencies = [ "cargo_toml", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -5671,9 +5673,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" @@ -6557,7 +6559,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -6568,7 +6570,7 @@ checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -7844,6 +7846,28 @@ dependencies = [ "sp-weights", ] +[[package]] +name = "pallet-score-staking" +version = "0.1.0" +dependencies = [ + "core-primitives", + "frame-benchmarking", + "frame-support", + "frame-system", + "num-integer", + "pallet-balances", + "pallet-parachain-staking", + "parity-scale-codec", + "scale-info", + "serde", + "serde_json", + "sp-core", + "sp-io", + "sp-keyring", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-session" version = "4.0.0-dev" @@ -7926,7 +7950,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -8421,7 +8445,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -8462,7 +8486,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -9786,7 +9810,7 @@ dependencies = [ "proc-macro2", "quote", "sha3", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -9901,7 +9925,7 @@ checksum = "0e99670bafb56b9a106419397343bdbc8b8742c3cc449fec6345f86173f47cd4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -10297,7 +10321,7 @@ checksum = "2dfaf0c85b766276c797f3791f5bc6d5bd116b41d53049af2789666b0c0bc9fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -10560,6 +10584,7 @@ dependencies = [ "pallet-preimage", "pallet-proxy", "pallet-scheduler", + "pallet-score-staking", "pallet-session", "pallet-sudo", "pallet-teebag", @@ -11110,7 +11135,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -12086,7 +12111,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -12357,29 +12382,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", @@ -12681,7 +12706,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -12923,7 +12948,7 @@ dependencies = [ "proc-macro2", "quote", "sp-core-hashing", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -12942,7 +12967,7 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -13153,7 +13178,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -13321,7 +13346,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -13520,7 +13545,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -13694,9 +13719,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" dependencies = [ "proc-macro2", "quote", @@ -13793,7 +13818,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -13962,7 +13987,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -14143,7 +14168,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -14186,7 +14211,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -14624,7 +14649,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", "wasm-bindgen-shared", ] @@ -14658,7 +14683,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -15795,7 +15820,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -15903,7 +15928,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 750d8ef5f2..2a14f01621 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ members = [ 'pallets/group', 'pallets/identity-management', 'pallets/parachain-staking', + 'pallets/score-staking', 'pallets/teebag', 'pallets/vc-management', 'pallets/xcm-asset-manager', @@ -48,7 +49,7 @@ strip = "symbols" incremental = false [workspace.dependencies] -async-trait = { version = "0.1.80" } +async-trait = { version = "0.1.81" } assert_matches = { version = "1.3.0" } blake2-rfc = { version = "0.2.18", default-features = false } base58 = { version = "0.2", default-features = false } @@ -77,6 +78,7 @@ tokio = { version = "1.38.0", features = ["macros", "sync"] } strum = { version = "0.26", default-features = false } strum_macros = { version = "0.26", default-features = false } num_enum = { version = "0.7.2", default-features = false } +num-integer = { version = "0.1", default-features = false } rustc-hex = { version = "2.0.1", default-features = false } x509-cert = { version = "0.1.0", default-features = false, features = ["alloc"] } ring = { version = "0.16.20", default-features = false, features = ["alloc"] } @@ -252,6 +254,7 @@ pallet-extrinsic-filter = { path = "pallets/extrinsic-filter", default-features pallet-group = { path = "pallets/group", default-features = false } pallet-identity-management = { path = "pallets/identity-management", default-features = false } pallet-parachain-staking = { path = "pallets/parachain-staking", default-features = false } +pallet-score-staking = { path = "pallets/score-staking", default-features = false } pallet-teebag = { path = "pallets/teebag", default-features = false } pallet-vc-management = { path = "pallets/vc-management", default-features = false } precompile-utils = { path = "precompiles/utils", default-features = false } diff --git a/bitacross-worker/Cargo.lock b/bitacross-worker/Cargo.lock index 5bb3fede85..a6f8424a51 100644 --- a/bitacross-worker/Cargo.lock +++ b/bitacross-worker/Cargo.lock @@ -2893,7 +2893,6 @@ dependencies = [ "itp-top-pool-author", "itp-types", "itp-utils", - "lc-scheduled-enclave", "litentry-hex-utils", "litentry-primitives", "log 0.4.20", @@ -3096,7 +3095,6 @@ dependencies = [ "itp-test", "itp-top-pool-author", "itp-types", - "lc-scheduled-enclave", "litentry-primitives", "log 0.4.20", "parity-scale-codec", @@ -4021,22 +4019,6 @@ dependencies = [ "sp-io 7.0.0 (git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.42)", ] -[[package]] -name = "lc-scheduled-enclave" -version = "0.8.0" -dependencies = [ - "itp-settings", - "itp-sgx-io", - "itp-types", - "lazy_static", - "log 0.4.20", - "parity-scale-codec", - "sgx_tstd", - "sp-std", - "thiserror 1.0.44", - "thiserror 1.0.9", -] - [[package]] name = "lc-teebag-storage" version = "0.1.0" diff --git a/bitacross-worker/Makefile b/bitacross-worker/Makefile index dec8fc9ec6..e15b35e93d 100755 --- a/bitacross-worker/Makefile +++ b/bitacross-worker/Makefile @@ -27,6 +27,7 @@ SGX_PRODUCTION ?= 0 ######## Worker Feature Settings ######## # Set offchain-worker as default feature mode WORKER_MODE ?= offchain-worker +RA_METHOD ?= SKIP_WASM_BUILD = 1 # include the build settings from rust-sgx-sdk @@ -76,17 +77,17 @@ ifeq ($(SGX_PRODUCTION), 1) SGX_ENCLAVE_CONFIG = "enclave-runtime/Enclave.config.production.xml" SGX_SIGN_KEY = $(SGX_COMMERCIAL_KEY) SGX_SIGN_PASSFILE = $(SGX_PASSFILE) - WORKER_FEATURES := --features=link-binary,$(WORKER_MODE),$(WORKER_FEATURES),$(ADDITIONAL_FEATURES) + WORKER_FEATURES := --features=link-binary,$(WORKER_MODE),$(RA_METHOD),$(WORKER_FEATURES),$(ADDITIONAL_FEATURES) else SGX_ENCLAVE_MODE = "Development Mode" SGX_ENCLAVE_CONFIG = "enclave-runtime/Enclave.config.xml" SGX_SIGN_KEY = "enclave-runtime/Enclave_private.pem" SGX_SIGN_PASSFILE = "" - WORKER_FEATURES := --features=default,development,link-binary,$(WORKER_MODE),$(WORKER_FEATURES),$(ADDITIONAL_FEATURES) + WORKER_FEATURES := --features=default,development,link-binary,$(WORKER_MODE),$(RA_METHOD),$(WORKER_FEATURES),$(ADDITIONAL_FEATURES) ADDITIONAL_FEATURES := development endif -CLIENT_FEATURES = --features=$(WORKER_MODE),$(ADDITIONAL_FEATURES) +CLIENT_FEATURES = --features=$(WORKER_MODE),$(RA_METHOD),$(ADDITIONAL_FEATURES) # check if running on Jenkins ifdef BUILD_ID diff --git a/bitacross-worker/app-libs/parentchain-interface/Cargo.toml b/bitacross-worker/app-libs/parentchain-interface/Cargo.toml index 31d35e947e..926a3cea2b 100644 --- a/bitacross-worker/app-libs/parentchain-interface/Cargo.toml +++ b/bitacross-worker/app-libs/parentchain-interface/Cargo.toml @@ -35,7 +35,6 @@ sp-runtime = { default-features = false, git = "https://github.com/paritytech/su bc-enclave-registry = { path = "../../bitacross/core/bc-enclave-registry", default-features = false } bc-relayer-registry = { path = "../../bitacross/core/bc-relayer-registry", default-features = false } bc-signer-registry = { path = "../../bitacross/core/bc-signer-registry", default-features = false } -lc-scheduled-enclave = { path = "../../litentry/core/scheduled-enclave", default-features = false, optional = true } litentry-hex-utils = { path = "../../../primitives/hex", default-features = false } litentry-primitives = { path = "../../litentry/primitives", default-features = false } sp-std = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } @@ -73,7 +72,6 @@ std = [ "sp-runtime/std", "substrate-api-client", "litentry-primitives/std", - "lc-scheduled-enclave/std", "sp-std/std", "bc-enclave-registry/std", "bc-relayer-registry/std", @@ -88,7 +86,6 @@ sgx = [ "itp-stf-executor/sgx", "itp-top-pool-author/sgx", "litentry-primitives/sgx", - "lc-scheduled-enclave/sgx", "bc-enclave-registry/sgx", "bc-relayer-registry/sgx", "bc-signer-registry/sgx", diff --git a/bitacross-worker/app-libs/parentchain-interface/src/integritee/event_filter.rs b/bitacross-worker/app-libs/parentchain-interface/src/integritee/event_filter.rs index b872fb62dd..7007dbf511 100644 --- a/bitacross-worker/app-libs/parentchain-interface/src/integritee/event_filter.rs +++ b/bitacross-worker/app-libs/parentchain-interface/src/integritee/event_filter.rs @@ -23,8 +23,8 @@ use itp_node_api::api_client::StaticEvent; use itp_types::{ parentchain::{ events::{ - BalanceTransfer, BtcWalletGenerated, EnclaveAdded, EnclaveRemoved, RelayerAdded, - RelayerRemoved, ScheduledEnclaveRemoved, ScheduledEnclaveSet, + BalanceTransfer, BtcWalletGenerated, EnclaveAdded, EnclaveRemoved, EnclaveUnauthorized, + RelayerAdded, RelayerRemoved, }, FilterEvents, }, @@ -72,13 +72,7 @@ impl FilterEvents for FilterableEvents { self.filter() } - fn get_scheduled_enclave_removed_events( - &self, - ) -> Result, Self::Error> { - self.filter() - } - - fn get_scheduled_enclave_set_events(&self) -> Result, Self::Error> { + fn get_enclave_unauthorized_events(&self) -> Result, Self::Error> { self.filter() } diff --git a/bitacross-worker/app-libs/parentchain-interface/src/integritee/event_handler.rs b/bitacross-worker/app-libs/parentchain-interface/src/integritee/event_handler.rs index d2c09f32dd..1dd12a7748 100644 --- a/bitacross-worker/app-libs/parentchain-interface/src/integritee/event_handler.rs +++ b/bitacross-worker/app-libs/parentchain-interface/src/integritee/event_handler.rs @@ -27,10 +27,9 @@ use itc_parentchain_indirect_calls_executor::error::Error; use itp_stf_primitives::traits::IndirectExecutor; use itp_types::{ parentchain::{FilterEvents, HandleParentchainEvents, ParentchainEventProcessingError}, - MrEnclave, WorkerType, + WorkerType, }; -use lc_scheduled_enclave::{ScheduledEnclaveUpdater, GLOBAL_SCHEDULED_ENCLAVE}; -use litentry_primitives::{Address32, Identity, SidechainBlockNumber}; +use litentry_primitives::{Address32, Identity}; use log::*; use sp_core::{blake2_256, H256}; use sp_std::vec::Vec; @@ -39,33 +38,6 @@ use std::string::ToString; pub struct ParentchainEventHandler {} impl ParentchainEventHandler { - fn set_scheduled_enclave( - worker_type: WorkerType, - sbn: SidechainBlockNumber, - mrenclave: MrEnclave, - ) -> Result<(), Error> { - if worker_type != WorkerType::BitAcross { - warn!("Ignore SetScheduledEnclave due to wrong worker_type"); - return Ok(()) - } - GLOBAL_SCHEDULED_ENCLAVE.update(sbn, mrenclave)?; - - Ok(()) - } - - fn remove_scheduled_enclave( - worker_type: WorkerType, - sbn: SidechainBlockNumber, - ) -> Result<(), Error> { - if worker_type != WorkerType::BitAcross { - warn!("Ignore RemoveScheduledEnclave due to wrong worker_type"); - return Ok(()) - } - GLOBAL_SCHEDULED_ENCLAVE.remove(sbn)?; - - Ok(()) - } - fn add_relayer(relayer_registry: &RelayerRegistry, account: Identity) -> Result<(), Error> { info!("Adding Relayer Account to Registry: {:?}", account); relayer_registry.update(account).map_err(|e| { @@ -158,41 +130,6 @@ where fn handle_events(executor: &Executor, events: impl FilterEvents) -> Result, Error> { let mut handled_events: Vec = Vec::new(); - if let Ok(events) = events.get_scheduled_enclave_set_events() { - debug!("Handling ScheduledEnclaveSet events"); - events - .iter() - .try_for_each(|event| { - debug!("found ScheduledEnclaveSet event: {:?}", event); - let result = Self::set_scheduled_enclave( - event.worker_type, - event.sidechain_block_number, - event.mrenclave, - ); - handled_events.push(hash_of(&event)); - - result - }) - .map_err(|_| ParentchainEventProcessingError::ScheduledEnclaveSetFailure)?; - } - - if let Ok(events) = events.get_scheduled_enclave_removed_events() { - debug!("Handling ScheduledEnclaveRemoved events"); - events - .iter() - .try_for_each(|event| { - debug!("found ScheduledEnclaveRemoved event: {:?}", event); - let result = Self::remove_scheduled_enclave( - event.worker_type, - event.sidechain_block_number, - ); - handled_events.push(hash_of(&event)); - - result - }) - .map_err(|_| ParentchainEventProcessingError::ScheduledEnclaveRemovedFailure)?; - } - if let Ok(events) = events.get_relayer_added_events() { debug!("Handling RelayerAdded events"); let relayer_registry = executor.get_relayer_registry_updater(); diff --git a/bitacross-worker/app-libs/parentchain-interface/src/target_a/event_filter.rs b/bitacross-worker/app-libs/parentchain-interface/src/target_a/event_filter.rs index 5b9c712b31..01cfff5c73 100644 --- a/bitacross-worker/app-libs/parentchain-interface/src/target_a/event_filter.rs +++ b/bitacross-worker/app-libs/parentchain-interface/src/target_a/event_filter.rs @@ -22,8 +22,8 @@ use itp_node_api::api_client::StaticEvent; use itp_types::{ parentchain::{ events::{ - BalanceTransfer, BtcWalletGenerated, EnclaveAdded, EnclaveRemoved, RelayerAdded, - RelayerRemoved, ScheduledEnclaveRemoved, ScheduledEnclaveSet, + BalanceTransfer, BtcWalletGenerated, EnclaveAdded, EnclaveRemoved, EnclaveUnauthorized, + RelayerAdded, RelayerRemoved, }, FilterEvents, }, @@ -70,13 +70,7 @@ impl FilterEvents for FilterableEvents { self.filter() } - fn get_scheduled_enclave_removed_events( - &self, - ) -> Result, Self::Error> { - self.filter() - } - - fn get_scheduled_enclave_set_events(&self) -> Result, Self::Error> { + fn get_enclave_unauthorized_events(&self) -> Result, Self::Error> { self.filter() } diff --git a/bitacross-worker/app-libs/parentchain-interface/src/target_b/event_filter.rs b/bitacross-worker/app-libs/parentchain-interface/src/target_b/event_filter.rs index 5b9c712b31..01cfff5c73 100644 --- a/bitacross-worker/app-libs/parentchain-interface/src/target_b/event_filter.rs +++ b/bitacross-worker/app-libs/parentchain-interface/src/target_b/event_filter.rs @@ -22,8 +22,8 @@ use itp_node_api::api_client::StaticEvent; use itp_types::{ parentchain::{ events::{ - BalanceTransfer, BtcWalletGenerated, EnclaveAdded, EnclaveRemoved, RelayerAdded, - RelayerRemoved, ScheduledEnclaveRemoved, ScheduledEnclaveSet, + BalanceTransfer, BtcWalletGenerated, EnclaveAdded, EnclaveRemoved, EnclaveUnauthorized, + RelayerAdded, RelayerRemoved, }, FilterEvents, }, @@ -70,13 +70,7 @@ impl FilterEvents for FilterableEvents { self.filter() } - fn get_scheduled_enclave_removed_events( - &self, - ) -> Result, Self::Error> { - self.filter() - } - - fn get_scheduled_enclave_set_events(&self) -> Result, Self::Error> { + fn get_enclave_unauthorized_events(&self) -> Result, Self::Error> { self.filter() } diff --git a/bitacross-worker/app-libs/sgx-runtime/src/lib.rs b/bitacross-worker/app-libs/sgx-runtime/src/lib.rs index 19c9802ba3..05a44ceb9f 100644 --- a/bitacross-worker/app-libs/sgx-runtime/src/lib.rs +++ b/bitacross-worker/app-libs/sgx-runtime/src/lib.rs @@ -121,7 +121,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node-template"), impl_name: create_runtime_str!("node-template"), authoring_version: 1, - spec_version: 104, + spec_version: 105, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/bitacross-worker/bitacross/core/bc-musig2-ceremony/src/lib.rs b/bitacross-worker/bitacross/core/bc-musig2-ceremony/src/lib.rs index 58574a2ef3..a4609b60f9 100644 --- a/bitacross-worker/bitacross/core/bc-musig2-ceremony/src/lib.rs +++ b/bitacross-worker/bitacross/core/bc-musig2-ceremony/src/lib.rs @@ -106,7 +106,7 @@ pub enum CeremonyEvent { FirstRoundStarted(Signers, CeremonyId, PubNonce), SecondRoundStarted(Signers, CeremonyId, PartialSignature), CeremonyError(Signers, CeremonyError, RequestAesKey), - CeremonyEnded([u8; 64], RequestAesKey), + CeremonyEnded([u8; 64], RequestAesKey, bool, bool), CeremonyTimedOut(Signers, RequestAesKey), } @@ -136,10 +136,13 @@ pub struct MuSig2Ceremony> { second_round: Option>, ticks_left: u32, agg_key: Option, + // indicates whether it's check run - signature verification result is returned instead of signature + check_run: bool, } impl> MuSig2Ceremony { // Creates new ceremony and starts first round + #[allow(clippy::too_many_arguments)] pub fn new( me: SignerId, aes_key: RequestAesKey, @@ -148,6 +151,7 @@ impl> MuSig2Ceremony { commands: Vec, signing_key_access: Arc, ttl: u32, + check_run: bool, ) -> Result { info!("Creating new ceremony {:?} and events {:?}", payload, commands); if signers.len() < 3 { @@ -216,6 +220,7 @@ impl> MuSig2Ceremony { second_round: None, ticks_left: ttl, agg_key: Some(agg_key_copy), + check_run, }) } @@ -388,15 +393,13 @@ impl> MuSig2Ceremony { SignBitcoinPayload::TaprootSpendable(p, _) => p, SignBitcoinPayload::WithTweaks(p, _) => p, }; - - info!("Message {:?}", message); - - info!("Verification result: "); - match verify_single(self.agg_key.unwrap(), signature, message) { - Ok(_) => info!("OK!"), - Err(_) => info!("NOK!"), - }; - self.events.push(CeremonyEnded(signature.to_bytes(), self.aes_key)); + let result = verify_single(self.agg_key.unwrap(), signature, message).is_ok(); + self.events.push(CeremonyEnded( + signature.to_bytes(), + self.aes_key, + self.check_run, + result, + )); } } Ok(()) @@ -555,6 +558,7 @@ pub mod test { vec![], Arc::new(signing_key_access), 10, + false, ); // then @@ -575,6 +579,7 @@ pub mod test { vec![], Arc::new(signing_key_access), 10, + false, ); // then @@ -595,6 +600,7 @@ pub mod test { vec![], Arc::new(signing_key_access), 10, + false, ) .unwrap(); @@ -623,6 +629,7 @@ pub mod test { vec![], Arc::new(signing_key_access), 10, + false, ) .unwrap(); @@ -649,6 +656,7 @@ pub mod test { vec![save_signer1_nonce_cmd()], Arc::new(signing_key_access), 10, + false, ) .unwrap(); @@ -679,6 +687,7 @@ pub mod test { ], Arc::new(signing_key_access), 10, + false, ) .unwrap(); @@ -708,6 +717,7 @@ pub mod test { vec![unknown_signer_nonce_cmd()], Arc::new(signing_key_access), 10, + false, ) .unwrap(); @@ -770,6 +780,7 @@ pub mod sgx_tests { vec![], Arc::new(my_signer_key_access), 10, + false, ) .unwrap(); // signer 1 @@ -782,6 +793,7 @@ pub mod sgx_tests { vec![], Arc::new(signer1_key_access), 10, + false, ) .unwrap(); // signer 2 @@ -794,6 +806,7 @@ pub mod sgx_tests { vec![], Arc::new(signer2_key_access), 10, + false, ) .unwrap(); @@ -883,21 +896,21 @@ pub mod sgx_tests { let signer2_ceremony_ceremony_ended_ev = signer2_ceremony_events.get(0).unwrap(); let my_ceremony_final_signature = match my_ceremony_ceremony_ended_ev { - CeremonyEvent::CeremonyEnded(signature, _) => signature.clone(), + CeremonyEvent::CeremonyEnded(signature, _, _, _) => signature.clone(), _ => { panic!("Ceremony should be ended") }, }; let signer1_ceremony_final_signature = match signer1_ceremony_ceremony_ended_ev { - CeremonyEvent::CeremonyEnded(signature, _) => signature.clone(), + CeremonyEvent::CeremonyEnded(signature, _, _, _) => signature.clone(), _ => { panic!("Ceremony should be ended") }, }; let signer2_ceremony_final_signature = match signer2_ceremony_ceremony_ended_ev { - CeremonyEvent::CeremonyEnded(signature, _) => signature.clone(), + CeremonyEvent::CeremonyEnded(signature, _, _, _) => signature.clone(), _ => { panic!("Ceremony should be ended") }, diff --git a/bitacross-worker/bitacross/core/bc-musig2-runner/src/lib.rs b/bitacross-worker/bitacross/core/bc-musig2-runner/src/lib.rs index 87fbe87b63..f0cf242618 100644 --- a/bitacross-worker/bitacross/core/bc-musig2-runner/src/lib.rs +++ b/bitacross-worker/bitacross/core/bc-musig2-runner/src/lib.rs @@ -26,7 +26,7 @@ compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the sam use bc_enclave_registry::EnclaveRegistryLookup; use codec::Encode; use core::time::Duration; -use itc_direct_rpc_client::{Response, RpcClient, RpcClientFactory}; +use itc_direct_rpc_client::{RpcClient, RpcClientFactory}; use itc_direct_rpc_server::SendRpcResponse; use itp_ocall_api::EnclaveAttestationOCallApi; use itp_sgx_crypto::{ @@ -55,11 +55,9 @@ use litentry_primitives::{aes_encrypt_default, Address32, AesRequest, Identity, #[cfg(feature = "sgx")] use std::sync::SgxMutex as Mutex; use std::{ + collections::HashMap, string::ToString, - sync::{ - mpsc::{sync_channel, SyncSender}, - Arc, - }, + sync::{mpsc::channel, Arc}, vec, }; @@ -82,27 +80,45 @@ pub fn init_ceremonies_thread + Send + Sync + 'static, Responder: SendRpcResponse + 'static, { - let (responses_sender, responses_receiver) = sync_channel(1000); + let (responses_sender, responses_receiver) = channel(); std::thread::spawn(move || { let my_identity: Address32 = signing_key_access.retrieve_key().unwrap().public().0.into(); let identity = Identity::Substrate(my_identity); + let mut peers_map = HashMap::new(); + let mut ceremonies_to_remove = vec![]; loop { + enclave_registry.get_all().iter().for_each(|(identity, address)| { + if my_identity != *identity && !peers_map.contains_key(identity.as_ref()) { + info!("creating new connection to peer: {:?}", address); + match client_factory.create(address, responses_sender.clone()) { + Ok(client) => { + peers_map.insert(*identity.as_ref(), client); + }, + Err(e) => error!("Could not connect to peer {}, reason: {:?}", address, e), + } + } + }); { - let mut ceremonies_to_remove = vec![]; - // do not hold lock for too long let ceremonies_to_process: Vec = - ceremony_registry.lock().unwrap().keys().cloned().collect(); + if let Ok(ceremonies) = ceremony_registry.try_lock() { + ceremonies.keys().cloned().collect() + } else { + warn!("Could not determine ceremonies to process"); + vec![] + }; for ceremony_id_to_process in ceremonies_to_process { // do not hold lock for too long as logic below includes I/O - let events = if let Some(ceremony) = - ceremony_registry.lock().unwrap().get_mut(&ceremony_id_to_process) - { - ceremony.tick() + let events = if let Ok(mut ceremonies) = ceremony_registry.try_lock() { + if let Some(ceremony) = ceremonies.get_mut(&ceremony_id_to_process) { + ceremony.tick() + } else { + warn!("Could not find ceremony with id: {:?}", ceremony_id_to_process); + vec![] + } } else { - warn!("Could not find ceremony with id: {:?}", ceremony_id_to_process); - continue + vec![] }; trace!("Got ceremony {:?} events {:?}", ceremony_id_to_process, events); @@ -136,12 +152,10 @@ pub fn init_ceremonies_thread( &request, + signer_id, + &mut peers_map, ); }); }, @@ -168,28 +182,34 @@ pub fn init_ceremonies_thread( &request, + signer_id, + &mut peers_map, ); }); }, - CeremonyEvent::CeremonyEnded(signature, request_aes_key) => { + CeremonyEvent::CeremonyEnded( + signature, + request_aes_key, + is_check_run, + verification_result, + ) => { debug!( "Ceremony {:?} ended, signature {:?}", ceremony_id_to_process, signature ); let hash = blake2_256(&ceremony_id_to_process.encode()); - let result = signature; - let encrypted_result = - aes_encrypt_default(&request_aes_key, &result.encode()) - .encode(); + let result = if is_check_run { + verification_result.encode() + } else { + let result = signature; + + aes_encrypt_default(&request_aes_key, &result.encode()).encode() + }; if let Err(e) = responder.send_state_with_status( Hash::from_slice(&hash), - encrypted_result, + result, DirectRequestStatus::Ok, ) { error!( @@ -197,6 +217,7 @@ pub fn init_ceremonies_thread { @@ -240,13 +261,7 @@ pub fn init_ceremonies_thread(&request, &mut peers_map); }); }, CeremonyEvent::CeremonyTimedOut(signers, request_aes_key) => { @@ -290,40 +305,43 @@ pub fn init_ceremonies_thread(&request, &mut peers_map); }); }, } } } - let mut ceremony_commands = ceremony_commands.lock().unwrap(); - let mut ceremony_registry = ceremony_registry.lock().unwrap(); - ceremony_commands.retain(|_, ceremony_pending_commands| { - ceremony_pending_commands.retain_mut(|c| { - c.tick(); - c.ticks_left > 0 + let ceremony_commands = ceremony_commands.try_lock(); + let ceremony_registry = ceremony_registry.try_lock(); + + if let Ok(mut ceremony_commands) = ceremony_commands { + ceremony_commands.retain(|_, ceremony_pending_commands| { + ceremony_pending_commands.retain_mut(|c| { + c.tick(); + c.ticks_left > 0 + }); + !ceremony_pending_commands.is_empty() }); - !ceremony_pending_commands.is_empty() - }); - - ceremonies_to_remove.iter().for_each(|ceremony_id| { - debug!("Removing ceremony {:?}", ceremony_id); - let _ = ceremony_registry.remove_entry(ceremony_id); - let _ = ceremony_commands.remove_entry(ceremony_id); - }); + + if let Ok(mut ceremonies) = ceremony_registry { + ceremonies_to_remove.iter().for_each(|ceremony_id| { + debug!("Removing ceremony {:?}", ceremony_id); + let _ = ceremonies.remove_entry(ceremony_id); + let _ = ceremony_commands.remove_entry(ceremony_id); + }); + ceremonies_to_remove = vec![]; + } else { + warn!("Could not get ceremonies lock"); + } + } else { + warn!("Could not get ceremony commands lock"); + } } std::thread::sleep(Duration::from_millis(1)) } }); - // here we will process all responses std::thread::spawn(move || { while let Ok((_id, rpc_return_value)) = responses_receiver.recv() { @@ -335,28 +353,31 @@ pub fn init_ceremonies_thread( - client_factory: &Arc, - enclave_registry: &Arc, - responses_sender: &SyncSender, +fn send_to_signer( + request: &RpcRequest, signer_id: &SignerId, + peers: &mut HashMap, +) where + ClientFactory: RpcClientFactory, +{ + if let Some(client) = peers.get_mut(signer_id) { + if let Err(e) = client.send(request) { + error!("Could not send request to signer: {:?}, reason: {:?}", signer_id, e) + } + } +} + +fn send_to_all_signers( request: &RpcRequest, + peers: &mut HashMap, ) where - ClientFactory: RpcClientFactory + Send + Sync + 'static, - ER: EnclaveRegistryLookup + Send + Sync + 'static, + ClientFactory: RpcClientFactory, { - enclave_registry.get_all().iter().for_each(|(identity, address)| { - if signer_id == identity.as_ref() { - trace!("creating new connection to peer: {:?}", address); - match client_factory.create(address, responses_sender.clone()) { - Ok(mut client) => - if let Err(e) = client.send(address, request) { - error!("Could not send request to signer: {:?}, reason: {:?}", signer_id, e) - }, - Err(e) => error!("Could not connect to peer {}, reason: {:?}", address, e), - } + for (signer_id, client) in peers.iter_mut() { + if let Err(e) = client.send(request) { + error!("Could not send request to signer: {:?}, reason: {:?}", signer_id, e) } - }); + } } fn prepare_request( diff --git a/bitacross-worker/bitacross/core/bc-relayer-registry/src/lib.rs b/bitacross-worker/bitacross/core/bc-relayer-registry/src/lib.rs index 4736bd1038..337b958a82 100644 --- a/bitacross-worker/bitacross/core/bc-relayer-registry/src/lib.rs +++ b/bitacross-worker/bitacross/core/bc-relayer-registry/src/lib.rs @@ -130,7 +130,7 @@ pub trait RelayerRegistryUpdater { } pub trait RelayerRegistryLookup { - fn contains_key(&self, account: Identity) -> bool; + fn contains_key(&self, account: &Identity) -> bool; } impl RelayerRegistryUpdater for RelayerRegistry { @@ -192,15 +192,15 @@ impl RelayerRegistryUpdater for RelayerRegistry { impl RelayerRegistryLookup for RelayerRegistry { #[cfg(feature = "std")] - fn contains_key(&self, account: Identity) -> bool { + fn contains_key(&self, account: &Identity) -> bool { let registry = self.registry.read().unwrap(); - registry.contains_key(&account) + registry.contains_key(account) } #[cfg(feature = "sgx")] - fn contains_key(&self, account: Identity) -> bool { + fn contains_key(&self, account: &Identity) -> bool { // Using unwrap becaused poisoned locks are unrecoverable errors let registry = self.registry.read().unwrap(); - registry.contains_key(&account) + registry.contains_key(account) } } diff --git a/bitacross-worker/bitacross/core/bc-task-receiver/src/lib.rs b/bitacross-worker/bitacross/core/bc-task-receiver/src/lib.rs index 6087eac22d..314cda29ff 100644 --- a/bitacross-worker/bitacross/core/bc-task-receiver/src/lib.rs +++ b/bitacross-worker/bitacross/core/bc-task-receiver/src/lib.rs @@ -42,7 +42,7 @@ use std::sync::SgxMutex as Mutex; use core::ops::Deref; -use bc_musig2_ceremony::{CeremonyCommandsRegistry, CeremonyRegistry}; +use bc_musig2_ceremony::{CeremonyCommandsRegistry, CeremonyRegistry, SignBitcoinPayload}; use bc_task_sender::{init_bit_across_task_sender_storage, BitAcrossProcessingResult}; use codec::{Decode, Encode}; use frame_support::{ensure, sp_runtime::app_crypto::sp_core::blake2_256}; @@ -245,10 +245,12 @@ where signer, payload, aes_key, + false, context.relayer_registry_lookup.deref(), context.musig2_ceremony_registry.clone(), context.musig2_ceremony_pending_commands.clone(), context.signer_registry_lookup.clone(), + context.enclave_registry_lookup.as_ref(), &context.signing_key_pub, context.bitcoin_key_repository.clone(), ) @@ -258,6 +260,29 @@ where })?; Ok(BitAcrossProcessingResult::Submitted(hash)) }, + DirectCall::CheckSignBitcoin(signer) => { + let payload = SignBitcoinPayload::Derived([0u8; 32].to_vec()); + let aes_key = [0u8; 32]; + let hash = blake2_256(&payload.encode()); + sign_bitcoin::handle( + signer, + payload, + aes_key, + true, + context.relayer_registry_lookup.deref(), + context.musig2_ceremony_registry.clone(), + context.musig2_ceremony_pending_commands.clone(), + context.signer_registry_lookup.clone(), + context.enclave_registry_lookup.as_ref(), + &context.signing_key_pub, + context.bitcoin_key_repository.clone(), + ) + .map_err(|e| { + error!("SignBitcoinCheck error: {:?}", e); + aes_encrypt_default(&aes_key, &e.encode()).encode() + })?; + Ok(BitAcrossProcessingResult::Submitted(hash)) + }, DirectCall::SignEthereum(signer, aes_key, msg) => sign_ethereum::handle( signer, msg, diff --git a/bitacross-worker/build.Dockerfile b/bitacross-worker/build.Dockerfile index 8cd65e9ced..f7b640fb45 100644 --- a/bitacross-worker/build.Dockerfile +++ b/bitacross-worker/build.Dockerfile @@ -147,6 +147,11 @@ ARG UID=1000 RUN adduser -u ${UID} --disabled-password --gecos '' litentry RUN adduser -u ${UID} litentry sudo RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers +# to fix Multi-node distributed worker encounters SGX permission errors. +RUN groupadd -g 121 sgx_prv && \ + groupadd -g 108 sgx && \ + usermod -aG sgx litentry && \ + usermod -aG sgx_prv litentry COPY --from=local-builder:latest /opt/sgxsdk /opt/sgxsdk COPY --from=local-builder:latest /lib/x86_64-linux-gnu/libsgx* /lib/x86_64-linux-gnu/ diff --git a/bitacross-worker/core-primitives/enclave-api/ffi/src/lib.rs b/bitacross-worker/core-primitives/enclave-api/ffi/src/lib.rs index 60a4f95088..187f8a53e2 100644 --- a/bitacross-worker/core-primitives/enclave-api/ffi/src/lib.rs +++ b/bitacross-worker/core-primitives/enclave-api/ffi/src/lib.rs @@ -237,7 +237,6 @@ extern "C" { pub fn migrate_shard( eid: sgx_enclave_id_t, retval: *mut sgx_status_t, - old_shard: *const u8, new_shard: *const u8, shard_size: u32, ) -> sgx_status_t; diff --git a/bitacross-worker/core-primitives/enclave-api/src/enclave_base.rs b/bitacross-worker/core-primitives/enclave-api/src/enclave_base.rs index 8757e38a2b..4079052a60 100644 --- a/bitacross-worker/core-primitives/enclave-api/src/enclave_base.rs +++ b/bitacross-worker/core-primitives/enclave-api/src/enclave_base.rs @@ -79,7 +79,7 @@ pub trait EnclaveBase: Send + Sync + 'static { fn get_fingerprint(&self) -> EnclaveResult; // litentry - fn migrate_shard(&self, old_shard: Vec, new_shard: Vec) -> EnclaveResult<()>; + fn migrate_shard(&self, new_shard: Vec) -> EnclaveResult<()>; /// Publish generated wallets on parachain fn publish_wallets(&self) -> EnclaveResult<()>; @@ -391,16 +391,15 @@ mod impl_ffi { Ok(mr_enclave.into()) } - fn migrate_shard(&self, old_shard: Vec, new_shard: Vec) -> EnclaveResult<()> { + fn migrate_shard(&self, new_shard: Vec) -> EnclaveResult<()> { let mut retval = sgx_status_t::SGX_SUCCESS; let result = unsafe { ffi::migrate_shard( self.eid, &mut retval, - old_shard.as_ptr(), new_shard.as_ptr(), - old_shard.len() as u32, + new_shard.len() as u32, ) }; diff --git a/bitacross-worker/core-primitives/node-api/metadata/src/metadata_mocks.rs b/bitacross-worker/core-primitives/node-api/metadata/src/metadata_mocks.rs index 3d2bc56947..c4b66a273c 100644 --- a/bitacross-worker/core-primitives/node-api/metadata/src/metadata_mocks.rs +++ b/bitacross-worker/core-primitives/node-api/metadata/src/metadata_mocks.rs @@ -37,8 +37,8 @@ impl TryFrom for Metadata { pub struct NodeMetadataMock { // teebag teebag_module: u8, - set_scheduled_enclave: u8, - remove_scheduled_enclave: u8, + force_add_authorized_enclave: u8, + force_remove_authorized_enclave: u8, register_enclave: u8, unregister_enclave: u8, register_quoting_enclave: u8, @@ -78,8 +78,8 @@ impl NodeMetadataMock { pub fn new() -> Self { NodeMetadataMock { teebag_module: 50u8, - set_scheduled_enclave: 0u8, - remove_scheduled_enclave: 1u8, + force_add_authorized_enclave: 0u8, + force_remove_authorized_enclave: 1u8, register_enclave: 2u8, unregister_enclave: 3u8, register_quoting_enclave: 4u8, @@ -118,11 +118,11 @@ impl NodeMetadataMock { } impl TeebagCallIndexes for NodeMetadataMock { - fn set_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]> { - Ok([self.teebag_module, self.set_scheduled_enclave]) + fn force_add_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.teebag_module, self.force_add_authorized_enclave]) } - fn remove_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]> { - Ok([self.teebag_module, self.remove_scheduled_enclave]) + fn force_remove_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.teebag_module, self.force_remove_authorized_enclave]) } fn register_enclave_call_indexes(&self) -> Result<[u8; 2]> { Ok([self.teebag_module, self.register_enclave]) diff --git a/bitacross-worker/core-primitives/node-api/metadata/src/pallet_teebag.rs b/bitacross-worker/core-primitives/node-api/metadata/src/pallet_teebag.rs index b748dd632f..ddd7cf062f 100644 --- a/bitacross-worker/core-primitives/node-api/metadata/src/pallet_teebag.rs +++ b/bitacross-worker/core-primitives/node-api/metadata/src/pallet_teebag.rs @@ -21,9 +21,9 @@ pub const TEEBAG: &str = "Teebag"; // we only list the extrinsics that we care pub trait TeebagCallIndexes { - fn set_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]>; + fn force_add_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]>; - fn remove_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]>; + fn force_remove_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]>; fn register_enclave_call_indexes(&self) -> Result<[u8; 2]>; @@ -41,11 +41,11 @@ pub trait TeebagCallIndexes { } impl TeebagCallIndexes for NodeMetadata { - fn set_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]> { - self.call_indexes(TEEBAG, "set_scheduled_enclave") + fn force_add_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(TEEBAG, "force_add_authorized_enclave") } - fn remove_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]> { - self.call_indexes(TEEBAG, "remove_scheduled_enclave") + fn force_remove_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(TEEBAG, "force_remove_authorized_enclave") } fn register_enclave_call_indexes(&self) -> Result<[u8; 2]> { self.call_indexes(TEEBAG, "register_enclave") diff --git a/bitacross-worker/core-primitives/settings/src/lib.rs b/bitacross-worker/core-primitives/settings/src/lib.rs index 95d75aab92..9fab0b4adf 100644 --- a/bitacross-worker/core-primitives/settings/src/lib.rs +++ b/bitacross-worker/core-primitives/settings/src/lib.rs @@ -36,9 +36,6 @@ pub mod files { /// Path to the light-client db for the Target B parentchain. pub const TARGET_B_PARENTCHAIN_LIGHT_CLIENT_DB_PATH: &str = "target_b_lcdb"; - // litentry - pub const SCHEDULED_ENCLAVE_FILE: &str = "scheduled_enclave_sealed.bin"; - // bitacross pub const RELAYER_REGISTRY_FILE: &str = "relayer_registry_sealed.bin"; diff --git a/bitacross-worker/core-primitives/stf-executor/src/enclave_signer.rs b/bitacross-worker/core-primitives/stf-executor/src/enclave_signer.rs index 82fee8f835..21264b381a 100644 --- a/bitacross-worker/core-primitives/stf-executor/src/enclave_signer.rs +++ b/bitacross-worker/core-primitives/stf-executor/src/enclave_signer.rs @@ -32,7 +32,7 @@ use itp_stf_primitives::{ }; use itp_stf_state_observer::traits::ObserveState; use itp_top_pool_author::traits::AuthorApi; -use itp_types::{Index, ShardIdentifier}; +use itp_types::{Index, MrEnclave, ShardIdentifier}; use log::*; use sp_core::{ed25519::Pair as Ed25519Pair, Pair}; use std::{boxed::Box, sync::Arc, vec::Vec}; @@ -117,12 +117,16 @@ where Ok(enclave_call_signing_key.public().into()) } + fn get_mrenclave(&self) -> Result { + Ok(self.ocall_api.get_mrenclave_of_self().map(|m| m.m)?) + } + fn sign_call_with_self>( &self, trusted_call: &TC, shard: &ShardIdentifier, ) -> Result { - let mr_enclave = self.ocall_api.get_mrenclave_of_self()?; + let mrenclave = self.get_mrenclave()?; let enclave_account = self.get_enclave_account()?; let enclave_call_signing_key = self.get_enclave_call_signing_key()?; @@ -138,7 +142,7 @@ where Ok(trusted_call.sign( &KeyPair::Ed25519(Box::new(enclave_call_signing_key)), adjusted_nonce, - &mr_enclave.m, + &mrenclave, shard, )) } diff --git a/bitacross-worker/core-primitives/stf-executor/src/mocks.rs b/bitacross-worker/core-primitives/stf-executor/src/mocks.rs index 95fde3f836..e0bc9c06e8 100644 --- a/bitacross-worker/core-primitives/stf-executor/src/mocks.rs +++ b/bitacross-worker/core-primitives/stf-executor/src/mocks.rs @@ -28,7 +28,7 @@ use itp_stf_primitives::{ traits::TrustedCallSigning, types::{AccountId, KeyPair, ShardIdentifier, TrustedOperationOrHash}, }; -use itp_types::H256; +use itp_types::{MrEnclave, H256}; use sp_core::Pair; use sp_runtime::traits::Header as HeaderTrait; #[cfg(feature = "std")] @@ -134,6 +134,10 @@ impl StfEnclaveSigning for StfEnclaveSigne Ok(self.signer.public().into()) } + fn get_mrenclave(&self) -> Result { + Ok(self.mr_enclave) + } + fn sign_call_with_self>( &self, trusted_call: &TC, diff --git a/bitacross-worker/core-primitives/stf-executor/src/traits.rs b/bitacross-worker/core-primitives/stf-executor/src/traits.rs index ad4f2c0900..ebfb9f0858 100644 --- a/bitacross-worker/core-primitives/stf-executor/src/traits.rs +++ b/bitacross-worker/core-primitives/stf-executor/src/traits.rs @@ -23,7 +23,7 @@ use itp_stf_primitives::{ traits::TrustedCallSigning, types::{AccountId, ShardIdentifier, TrustedOperation}, }; -use itp_types::H256; +use itp_types::{MrEnclave, H256}; use sp_runtime::traits::Header as HeaderTrait; use std::{time::Duration, vec::Vec}; @@ -42,6 +42,8 @@ where { fn get_enclave_account(&self) -> Result; + fn get_mrenclave(&self) -> Result; + fn sign_call_with_self>( &self, trusted_call: &TC, diff --git a/bitacross-worker/core-primitives/stf-state-handler/src/handle_state.rs b/bitacross-worker/core-primitives/stf-state-handler/src/handle_state.rs index 8dae3c1f43..af0439d3cc 100644 --- a/bitacross-worker/core-primitives/stf-state-handler/src/handle_state.rs +++ b/bitacross-worker/core-primitives/stf-state-handler/src/handle_state.rs @@ -74,10 +74,5 @@ pub trait HandleState { fn reset(&self, state: Self::StateT, shard: &ShardIdentifier) -> Result; // litentry - /// Migrate state from old shard to new shard - fn migrate_shard( - &self, - old_shard: ShardIdentifier, - new_shard: ShardIdentifier, - ) -> Result; + fn migrate_shard(&self, new_shard: ShardIdentifier) -> Result; } diff --git a/bitacross-worker/core-primitives/stf-state-handler/src/state_handler.rs b/bitacross-worker/core-primitives/stf-state-handler/src/state_handler.rs index 6acf2c579d..d662f2b6b3 100644 --- a/bitacross-worker/core-primitives/stf-state-handler/src/state_handler.rs +++ b/bitacross-worker/core-primitives/stf-state-handler/src/state_handler.rs @@ -228,11 +228,18 @@ where self.write_after_mutation(state, state_write_lock, shard) } - fn migrate_shard( - &self, - old_shard: ShardIdentifier, - new_shard: ShardIdentifier, - ) -> Result { + fn migrate_shard(&self, new_shard: ShardIdentifier) -> Result { + if self.shard_exists(&new_shard)? { + let (_, state_hash) = self.load_cloned(&new_shard)?; + return Ok(state_hash) + } + let old_shard = match self.list_shards()? { + shards if shards.len() == 1 => shards[0], + _ => + return Err(Error::Other( + "Cannot migrate shard if there is more than one shard".into(), + )), + }; let (state, _) = self.load_cloned(&old_shard)?; self.reset(state, &new_shard) } diff --git a/bitacross-worker/core-primitives/substrate-sgx/sp-io/src/lib.rs b/bitacross-worker/core-primitives/substrate-sgx/sp-io/src/lib.rs index 6962f6c164..57f655e85e 100644 --- a/bitacross-worker/core-primitives/substrate-sgx/sp-io/src/lib.rs +++ b/bitacross-worker/core-primitives/substrate-sgx/sp-io/src/lib.rs @@ -169,7 +169,7 @@ pub mod storage { pub fn clear(key: &[u8]) { with_externalities(|ext| { if ext.remove(key).is_none() { - info!("Tried to clear storage that was not existing"); + debug!("Tried to clear storage that was not existing"); } }); } @@ -272,7 +272,7 @@ pub mod storage { /// in unbalanced transactions. For example, FRAME users should use high level storage /// abstractions. pub fn start_transaction() { - warn!("storage::start_transaction unimplemented"); + debug!("storage::start_transaction unimplemented"); } /// Rollback the last transaction started by `start_transaction`. @@ -283,7 +283,7 @@ pub mod storage { /// /// Will panic if there is no open transaction. pub fn rollback_transaction() { - warn!("storage::rollback_transaction unimplemented"); + debug!("storage::rollback_transaction unimplemented"); } /// Commit the last transaction started by `start_transaction`. @@ -294,7 +294,7 @@ pub mod storage { /// /// Will panic if there is no open transaction. pub fn commit_transaction() { - warn!("storage::commit_transaction unimplemented"); + debug!("storage::commit_transaction unimplemented"); } } diff --git a/bitacross-worker/core-primitives/test/src/mock/handle_state_mock.rs b/bitacross-worker/core-primitives/test/src/mock/handle_state_mock.rs index 3776a0d9a9..9c8710935d 100644 --- a/bitacross-worker/core-primitives/test/src/mock/handle_state_mock.rs +++ b/bitacross-worker/core-primitives/test/src/mock/handle_state_mock.rs @@ -56,11 +56,8 @@ impl HandleState for HandleStateMock { self.reset(StfState::default(), &shard) } - fn migrate_shard( - &self, - old_shard: ShardIdentifier, - new_shard: ShardIdentifier, - ) -> Result { + fn migrate_shard(&self, new_shard: ShardIdentifier) -> Result { + let old_shard = *self.state_map.read().unwrap().keys().next().unwrap(); let (state, _) = self.load_cloned(&old_shard)?; self.reset(state, &new_shard) } @@ -228,7 +225,7 @@ pub mod tests { state.insert(key.encode(), value.encode()); state_handler.write_after_mutation(state, lock, &old_shard).unwrap(); - state_handler.migrate_shard(old_shard, new_shard).unwrap(); + state_handler.migrate_shard(new_shard).unwrap(); let (new_state, _) = state_handler.load_cloned(&new_shard).unwrap(); let inserted_value = new_state.get(key.encode().as_slice()).expect("value for key should exist"); diff --git a/bitacross-worker/core-primitives/types/src/lib.rs b/bitacross-worker/core-primitives/types/src/lib.rs index bc6849a06c..b1b74b3787 100644 --- a/bitacross-worker/core-primitives/types/src/lib.rs +++ b/bitacross-worker/core-primitives/types/src/lib.rs @@ -29,7 +29,8 @@ pub mod storage; pub use itp_sgx_runtime_primitives::types::*; pub use litentry_primitives::{ - AttestationType, DecryptableRequest, Enclave, EnclaveFingerprint, MrEnclave, WorkerType, + AttestationType, DcapProvider, DecryptableRequest, Enclave, EnclaveFingerprint, MrEnclave, + WorkerType, }; pub use sp_core::{crypto::AccountId32 as AccountId, H256}; diff --git a/bitacross-worker/core-primitives/types/src/parentchain/events.rs b/bitacross-worker/core-primitives/types/src/parentchain/events.rs index c1d729fa3f..919f2b2b29 100644 --- a/bitacross-worker/core-primitives/types/src/parentchain/events.rs +++ b/bitacross-worker/core-primitives/types/src/parentchain/events.rs @@ -1,11 +1,8 @@ use super::alloc::{format, vec::Vec}; -use crate::{ - AccountId, Balance, BlockNumber, Hash, MrEnclave, ShardIdentifier, SidechainBlockNumber, - WorkerType, -}; +use crate::{AccountId, Balance, BlockNumber, Hash, MrEnclave, ShardIdentifier, WorkerType}; use codec::{Decode, Encode}; use core::fmt::Debug; -use itp_utils::stringify::account_id_to_string; +use itp_utils::{hex::ToHexPrefixed, stringify::account_id_to_string}; use litentry_primitives::{Address32, Identity}; use substrate_api_client::ac_node_api::StaticEvent; @@ -74,50 +71,25 @@ impl StaticEvent for ParentchainBlockProcessed { } #[derive(Encode, Decode, Debug)] -pub struct ScheduledEnclaveSet { +pub struct EnclaveUnauthorized { pub worker_type: WorkerType, - pub sidechain_block_number: SidechainBlockNumber, pub mrenclave: MrEnclave, } -impl core::fmt::Display for ScheduledEnclaveSet { +impl core::fmt::Display for EnclaveUnauthorized { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { let message = format!( - "[{}:{}] :: worker_type: {:?}, sidechain_block_number: {}, mrenclave: {:?}", - ScheduledEnclaveSet::PALLET, - ScheduledEnclaveSet::EVENT, + "EnclaveUnauthorized :: worker_type: {:?}, mrenclave: {}", self.worker_type, - self.sidechain_block_number, - self.mrenclave + self.mrenclave.to_hex() ); write!(f, "{}", message) } } -impl StaticEvent for ScheduledEnclaveSet { +impl StaticEvent for EnclaveUnauthorized { const PALLET: &'static str = "Teebag"; - const EVENT: &'static str = "ScheduledEnclaveSet"; -} - -#[derive(Encode, Decode, Debug)] -pub struct ScheduledEnclaveRemoved { - pub worker_type: WorkerType, - pub sidechain_block_number: SidechainBlockNumber, -} - -impl core::fmt::Display for ScheduledEnclaveRemoved { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - let message = format!( - "ScheduledEnclaveRemoved :: worker_type: {:?}, sidechain_block_number: {}", - self.worker_type, self.sidechain_block_number - ); - write!(f, "{}", message) - } -} - -impl StaticEvent for ScheduledEnclaveRemoved { - const PALLET: &'static str = "Teebag"; - const EVENT: &'static str = "ScheduledEnclaveRemoved"; + const EVENT: &'static str = "EnclaveUnauthorized"; } #[derive(Encode, Decode, Debug)] diff --git a/bitacross-worker/core-primitives/types/src/parentchain/mod.rs b/bitacross-worker/core-primitives/types/src/parentchain/mod.rs index d9310f8b44..217466d2ff 100644 --- a/bitacross-worker/core-primitives/types/src/parentchain/mod.rs +++ b/bitacross-worker/core-primitives/types/src/parentchain/mod.rs @@ -22,8 +22,8 @@ use alloc::vec::Vec; use codec::{Decode, Encode}; use core::fmt::Debug; use events::{ - BalanceTransfer, BtcWalletGenerated, EnclaveAdded, EnclaveRemoved, RelayerAdded, - RelayerRemoved, ScheduledEnclaveRemoved, ScheduledEnclaveSet, + BalanceTransfer, BtcWalletGenerated, EnclaveAdded, EnclaveRemoved, EnclaveUnauthorized, + RelayerAdded, RelayerRemoved, }; use itp_stf_primitives::traits::{IndirectExecutor, TrustedCallVerification}; #[cfg(feature = "std")] @@ -97,11 +97,7 @@ pub trait FilterEvents { fn get_transfer_events(&self) -> core::result::Result, Self::Error>; - fn get_scheduled_enclave_set_events(&self) -> Result, Self::Error>; - - fn get_scheduled_enclave_removed_events( - &self, - ) -> Result, Self::Error>; + fn get_enclave_unauthorized_events(&self) -> Result, Self::Error>; fn get_relayer_added_events(&self) -> Result, Self::Error>; @@ -129,8 +125,7 @@ where pub enum ParentchainEventProcessingError { ShieldFundsFailure, FunctionalityDisabled, - ScheduledEnclaveSetFailure, - ScheduledEnclaveRemovedFailure, + EnclaveUnauthorizedFailure, RelayerAddFailure, RelayerRemoveFailure, EnclaveAddFailure, @@ -145,10 +140,8 @@ impl core::fmt::Display for ParentchainEventProcessingError { "Parentchain Event Processing Error: ShieldFundsFailure", ParentchainEventProcessingError::FunctionalityDisabled => "Parentchain Event Processing Error: FunctionalityDisabled", - ParentchainEventProcessingError::ScheduledEnclaveSetFailure => - "Parentchain Event Processing Error: ScheduledEnclaveSetFailure", - ParentchainEventProcessingError::ScheduledEnclaveRemovedFailure => - "Parentchain Event Processing Error: ScheduledEnclaveRemovedFailure", + ParentchainEventProcessingError::EnclaveUnauthorizedFailure => + "Parentchain Event Processing Error: EnclaveUnauthorizedFailure", ParentchainEventProcessingError::RelayerAddFailure => "Parentchain Event Processing Error: RelayerAddFailure", ParentchainEventProcessingError::RelayerRemoveFailure => diff --git a/bitacross-worker/core/direct-rpc-client/src/lib.rs b/bitacross-worker/core/direct-rpc-client/src/lib.rs index bb67de7736..69f5d95bfc 100644 --- a/bitacross-worker/core/direct-rpc-client/src/lib.rs +++ b/bitacross-worker/core/direct-rpc-client/src/lib.rs @@ -39,17 +39,27 @@ use alloc::format; use core::str::FromStr; -use itp_rpc::{Id, RpcRequest, RpcReturnValue}; +use log::{debug, error}; + +use serde_json::from_str; + +use itp_rpc::{Id, RpcRequest, RpcResponse, RpcReturnValue}; + +use itp_utils::FromHexPrefixed; use std::{ boxed::Box, error::Error, net::TcpStream, string::String, - sync::{mpsc::SyncSender, Arc}, + sync::{ + mpsc::{channel, Sender}, + Arc, + }, + time::Duration, vec::Vec, }; -use tungstenite::{client_tls_with_config, Connector, Message}; +use tungstenite::{client_tls_with_config, stream::MaybeTlsStream, Connector, Message, WebSocket}; use url::Url; use webpki::{DNSName, DNSNameRef}; @@ -92,7 +102,7 @@ pub trait RpcClientFactory { fn create( &self, url: &str, - response_sink: SyncSender, + response_sink: Sender, ) -> Result>; } @@ -104,32 +114,22 @@ impl RpcClientFactory for DirectRpcClientFactory { fn create( &self, url: &str, - response_sink: SyncSender, + response_sink: Sender, ) -> Result> { DirectRpcClient::new(url, response_sink) } } pub trait RpcClient { - fn send(&mut self, url: &str, request: &RpcRequest) -> Result<(), Box>; + fn send(&mut self, request: &RpcRequest) -> Result<(), Box>; } -pub struct DirectRpcClient {} - -impl DirectRpcClient { - pub fn new(_url: &str, _response_sink: SyncSender) -> Result> { - Ok(Self {}) - } -} - -#[derive(Clone)] -pub enum RequestParams { - Rsa(Vec), - Aes(Vec), +pub struct DirectRpcClient { + request_sink: Sender, } -impl RpcClient for DirectRpcClient { - fn send(&mut self, url: &str, request: &RpcRequest) -> Result<(), Box> { +impl DirectRpcClient { + pub fn new(url: &str, response_sink: Sender) -> Result> { let server_url = Url::from_str(url).map_err(|e| format!("Could not connect, reason: {:?}", e))?; let mut config = rustls::ClientConfig::new(); @@ -144,11 +144,119 @@ impl RpcClient for DirectRpcClient { client_tls_with_config(server_url.as_str(), stream, None, Some(connector)) .map_err(|e| format!("Could not open websocket connection: {:?}", e))?; + let (request_sender, request_receiver) = channel(); + + //it fails to perform handshake in non_blocking mode so we are setting it up after the handshake is performed + Self::switch_to_non_blocking(&mut socket); + + std::thread::spawn(move || { + loop { + // let's flush all pending requests first + while let Ok(request) = request_receiver.try_recv() { + if let Err(e) = socket.write_message(Message::Text(request)) { + error!("Could not write message to socket, reason: {:?}", e) + } + } + + if let Ok(message) = socket.read_message() { + if let Ok(Some(response)) = Self::handle_ws_message(message) { + if let Err(e) = response_sink.send(response) { + log::error!("Could not forward response, reason: {:?}", e) + }; + } + } + std::thread::sleep(Duration::from_millis(1)) + } + }); + debug!("Connected to peer: {}", url); + Ok(Self { request_sink: request_sender }) + } + + fn switch_to_non_blocking(socket: &mut WebSocket>) { + match socket.get_ref() { + MaybeTlsStream::Plain(stream) => { + stream.set_nonblocking(true).expect("set_nonblocking call failed"); + stream + .set_read_timeout(Some(Duration::from_millis(5))) + .expect("set_read_timeout call failed"); + }, + MaybeTlsStream::Rustls(stream) => { + stream.get_ref().set_nonblocking(true).expect("set_nonblocking call failed"); + stream + .get_ref() + .set_read_timeout(Some(Duration::from_millis(1))) + .expect("set_read_timeout call failed"); + }, + _ => {}, + } + } + + fn handle_ws_message(message: Message) -> Result, Box> { + match message { + Message::Text(text) => { + let rpc_response: RpcResponse = from_str(&text) + .map_err(|e| format!("Could not deserialize RpcResponse, reason: {:?}", e))?; + let return_value: RpcReturnValue = + RpcReturnValue::from_hex(&rpc_response.result) + .map_err(|e| format!("Could not deserialize value , reason: {:?}", e))?; + Ok(Some((rpc_response.id, return_value))) + }, + _ => { + log::warn!("Only text messages are supported"); + Ok(None) + }, + } + } +} + +#[derive(Clone)] +pub enum RequestParams { + Rsa(Vec), + Aes(Vec), +} + +impl RpcClient for DirectRpcClient { + fn send(&mut self, request: &RpcRequest) -> Result<(), Box> { let request = serde_json::to_string(request) .map_err(|e| format!("Could not parse RpcRequest {:?}", e))?; + self.request_sink + .send(request) + .map_err(|e| format!("Could not write message, reason: {:?}", e).into()) + } +} + +#[cfg(test)] +mod tests { + use crate::DirectRpcClient; + use itp_rpc::{Id, RpcResponse, RpcReturnValue}; + use itp_types::{DirectRequestStatus, TrustedOperationStatus, H256}; + use itp_utils::ToHexPrefixed; + use tungstenite::Message; + + #[test] + fn test_response_handling() { + let id = Id::Text( + "0x0000000000000000000000000000000000000000000000000000000000000000".to_owned(), + ); + let return_value: RpcReturnValue = RpcReturnValue::new( + vec![], + false, + DirectRequestStatus::TrustedOperationStatus( + TrustedOperationStatus::TopExecuted(vec![], true), + H256::random(), + ), + ); + let rpc_response: RpcResponse = RpcResponse { + jsonrpc: "2.0".to_owned(), + result: return_value.to_hex(), + id: id.clone(), + }; + let serialized_rpc_response = serde_json::to_string(&rpc_response).unwrap(); + let message = Message::text(serialized_rpc_response); + + let (result_id, result) = DirectRpcClient::handle_ws_message(message).unwrap().unwrap(); - log::trace!("Sending request: {:?}", request); - socket.write_message(Message::Text(request))?; - Ok(()) + assert_eq!(id, result_id); + assert_eq!(return_value, result); } } diff --git a/bitacross-worker/core/parentchain/indirect-calls-executor/Cargo.toml b/bitacross-worker/core/parentchain/indirect-calls-executor/Cargo.toml index 7bd496124e..a56e4c0cbe 100644 --- a/bitacross-worker/core/parentchain/indirect-calls-executor/Cargo.toml +++ b/bitacross-worker/core/parentchain/indirect-calls-executor/Cargo.toml @@ -42,7 +42,6 @@ sp-runtime = { default-features = false, git = "https://github.com/paritytech/su bc-enclave-registry = { path = "../../../bitacross/core/bc-enclave-registry", default-features = false } bc-relayer-registry = { path = "../../../bitacross/core/bc-relayer-registry", default-features = false } bc-signer-registry = { path = "../../../bitacross/core/bc-signer-registry", default-features = false } -lc-scheduled-enclave = { path = "../../../litentry/core/scheduled-enclave", default-features = false, optional = true } litentry-primitives = { path = "../../../litentry/primitives", default-features = false } [dev-dependencies] @@ -76,7 +75,6 @@ std = [ "thiserror", # litentry "litentry-primitives/std", - "lc-scheduled-enclave/std", "bc-relayer-registry/std", "bc-signer-registry/std", "bc-enclave-registry/std", @@ -92,7 +90,6 @@ sgx = [ "thiserror_sgx", # litentry "litentry-primitives/sgx", - "lc-scheduled-enclave/sgx", "bc-relayer-registry/sgx", "bc-signer-registry/sgx", "bc-enclave-registry/sgx", diff --git a/bitacross-worker/core/parentchain/indirect-calls-executor/src/error.rs b/bitacross-worker/core/parentchain/indirect-calls-executor/src/error.rs index c54f195890..e1c243507c 100644 --- a/bitacross-worker/core/parentchain/indirect-calls-executor/src/error.rs +++ b/bitacross-worker/core/parentchain/indirect-calls-executor/src/error.rs @@ -19,7 +19,6 @@ use crate::sgx_reexport_prelude::*; use itp_types::parentchain::ParentchainEventProcessingError; -use lc_scheduled_enclave::error::Error as ScheduledEnclaveError; use sgx_types::sgx_status_t; use sp_runtime::traits::LookupError; use std::{boxed::Box, format}; @@ -43,8 +42,6 @@ pub enum Error { Other(#[from] Box), #[error("AccountId lookup error")] AccountIdLookup, - #[error("ScheduledEnclave Error: {0:?}")] - ImportScheduledEnclave(ScheduledEnclaveError), } impl From for Error { @@ -82,9 +79,3 @@ impl From for Error { Self::AccountIdLookup } } - -impl From for Error { - fn from(e: ScheduledEnclaveError) -> Self { - Self::ImportScheduledEnclave(e) - } -} diff --git a/bitacross-worker/core/parentchain/indirect-calls-executor/src/mock.rs b/bitacross-worker/core/parentchain/indirect-calls-executor/src/mock.rs index 519c175f65..1d3e044e31 100644 --- a/bitacross-worker/core/parentchain/indirect-calls-executor/src/mock.rs +++ b/bitacross-worker/core/parentchain/indirect-calls-executor/src/mock.rs @@ -16,7 +16,7 @@ use itp_stf_primitives::{traits::IndirectExecutor, types::Signature}; use itp_test::mock::stf_mock::{GetterMock, TrustedCallMock, TrustedCallSignedMock}; use itp_types::{ parentchain::{ - events::{BalanceTransfer, ScheduledEnclaveRemoved, ScheduledEnclaveSet}, + events::{BalanceTransfer, EnclaveUnauthorized}, FilterEvents, HandleParentchainEvents, }, Address, RsaRequest, ShardIdentifier, H256, @@ -143,13 +143,7 @@ impl FilterEvents for MockEvents { Ok(Vec::from([transfer])) } - fn get_scheduled_enclave_set_events(&self) -> Result, Self::Error> { - Ok(Vec::new()) - } - - fn get_scheduled_enclave_removed_events( - &self, - ) -> Result, Self::Error> { + fn get_enclave_unauthorized_events(&self) -> Result, Self::Error> { Ok(Vec::new()) } diff --git a/bitacross-worker/core/tls-websocket-server/src/connection.rs b/bitacross-worker/core/tls-websocket-server/src/connection.rs index 10266f9b57..667d440b4b 100644 --- a/bitacross-worker/core/tls-websocket-server/src/connection.rs +++ b/bitacross-worker/core/tls-websocket-server/src/connection.rs @@ -28,9 +28,11 @@ use mio::{event::Event, net::TcpStream, Poll, Ready, Token}; use rustls::{ServerSession, Session}; use std::{ format, + io::ErrorKind, string::{String, ToString}, sync::Arc, time::Instant, + vec, }; use tungstenite::Message; @@ -131,31 +133,51 @@ where /// Read from a web-socket, or initiate handshake if websocket is not initialized yet. /// /// Returns a boolean 'connection should be closed'. - fn read_or_initialize_websocket(&mut self) -> WebSocketResult { + fn drain_message_or_initialize_websocket(&mut self) -> WebSocketResult { if let StreamState::Established(web_socket) = &mut self.stream_state { trace!( "Read is possible for connection {}: {}", self.connection_token.0, web_socket.can_read() ); - match web_socket.read_message() { - Ok(m) => - if let Err(e) = self.handle_message(m) { - error!( - "Failed to handle web-socket message (connection {}): {:?}", - self.connection_token.0, e - ); + + let mut messages = vec![]; + let mut is_closing = false; + + // Looping over 'read_message' is merely a workaround for the unexpected behavior of mio event triggering. + // Final solution will be applied in P-907. + loop { + match web_socket.read_message() { + Ok(m) => messages.push(m), + Err(e) => { + match e { + tungstenite::Error::Io(e) + if matches!(e.kind(), ErrorKind::WouldBlock) => {}, // no message to read + _ => { + trace!( + "Failed to read message from web-socket (connection {}): {:?}", + self.connection_token.0, + e + ); + is_closing = true; + }, + } + break }, - Err(e) => match e { - tungstenite::Error::ConnectionClosed => return Ok(true), - tungstenite::Error::AlreadyClosed => return Ok(true), - _ => error!( - "Failed to read message from web-socket (connection {}): {:?}", - self.connection_token.0, e - ), - }, + } } + + messages.into_iter().for_each(|m| { + if let Err(e) = self.handle_message(m) { + error!( + "Failed to handle web-socket message (connection {}): {:?}", + self.connection_token.0, e + ); + } + }); + trace!("Read successful for connection {}", self.connection_token.0); + Ok(is_closing) } else { trace!("Initialize connection {}", self.connection_token.0); self.stream_state = std::mem::take(&mut self.stream_state).attempt_handshake(); @@ -164,9 +186,8 @@ where return Ok(true) } debug!("Initialized connection {} successfully", self.connection_token.0); + Ok(false) } - - Ok(false) } fn handle_message(&mut self, message: Message) -> WebSocketResult<()> { @@ -283,7 +304,7 @@ where let connection_state = self.maybe_do_tls_read(); if connection_state.is_alive() { - is_closing = self.read_or_initialize_websocket()?; + is_closing = self.drain_message_or_initialize_websocket()?; } else { is_closing = connection_state.is_closing(); } diff --git a/bitacross-worker/docker/docker-compose.yml b/bitacross-worker/docker/docker-compose.yml index 585ca359ff..a077944fdc 100644 --- a/bitacross-worker/docker/docker-compose.yml +++ b/bitacross-worker/docker/docker-compose.yml @@ -134,6 +134,7 @@ services: - KARAT_DAO_API_URL=http://localhost:19527/karat_dao/ - MAGIC_CRAFT_API_URL=http://localhost:19527/magic_craft/ - MAGIC_CRAFT_API_KEY= + - DAREN_MARKET_API_URL=http://localhost:19527/daren_market/ - MORALIS_API_KEY= - NODEREAL_API_KEY=NODEREAL_API_KEY - NODEREAL_API_URL=http://localhost:19527 diff --git a/bitacross-worker/docker/multiworker-docker-compose.yml b/bitacross-worker/docker/multiworker-docker-compose.yml index 07201dfa90..5b3aa5108f 100644 --- a/bitacross-worker/docker/multiworker-docker-compose.yml +++ b/bitacross-worker/docker/multiworker-docker-compose.yml @@ -135,6 +135,7 @@ services: - KARAT_DAO_API_URL=http://localhost:19527/karat_dao/ - MAGIC_CRAFT_API_URL=http://localhost:19527/magic_craft/ - MAGIC_CRAFT_API_KEY= + - DAREN_MARKET_API_URL=http://localhost:19527/daren_market/ - MORALIS_API_KEY= - NODEREAL_API_KEY=NODEREAL_API_KEY - NODEREAL_API_URL=http://localhost:19527 @@ -193,6 +194,7 @@ services: - KARAT_DAO_API_URL=http://localhost:19527/karat_dao/ - MAGIC_CRAFT_API_URL=http://localhost:19527/magic_craft/ - MAGIC_CRAFT_API_KEY= + - DAREN_MARKET_API_URL=http://localhost:19527/daren_market/ - MORALIS_API_KEY= - NODEREAL_API_KEY=NODEREAL_API_KEY - NODEREAL_API_URL=http://localhost:19527 diff --git a/bitacross-worker/enclave-runtime/Cargo.lock b/bitacross-worker/enclave-runtime/Cargo.lock index bf84f41da0..6d3baa0106 100644 --- a/bitacross-worker/enclave-runtime/Cargo.lock +++ b/bitacross-worker/enclave-runtime/Cargo.lock @@ -1074,7 +1074,7 @@ dependencies = [ "itp-utils", "jsonrpc-core", "lazy_static", - "lc-scheduled-enclave", + "lc-direct-call", "litentry-hex-utils", "litentry-macros", "litentry-primitives", @@ -1957,7 +1957,6 @@ dependencies = [ "itp-stf-primitives", "itp-types", "itp-utils", - "lc-scheduled-enclave", "litentry-hex-utils", "litentry-primitives", "log", @@ -2143,7 +2142,6 @@ dependencies = [ "itp-test", "itp-top-pool-author", "itp-types", - "lc-scheduled-enclave", "litentry-primitives", "log", "parity-scale-codec", @@ -2740,21 +2738,6 @@ dependencies = [ "sp-io", ] -[[package]] -name = "lc-scheduled-enclave" -version = "0.8.0" -dependencies = [ - "itp-settings", - "itp-sgx-io", - "itp-types", - "lazy_static", - "log", - "parity-scale-codec", - "sgx_tstd", - "sp-std", - "thiserror", -] - [[package]] name = "lc-teebag-storage" version = "0.1.0" diff --git a/bitacross-worker/enclave-runtime/Cargo.toml b/bitacross-worker/enclave-runtime/Cargo.toml index e024602c6f..28307ca02e 100644 --- a/bitacross-worker/enclave-runtime/Cargo.toml +++ b/bitacross-worker/enclave-runtime/Cargo.toml @@ -135,7 +135,7 @@ bc-musig2-runner = { path = "../bitacross/core/bc-musig2-runner", default-featur bc-relayer-registry = { path = "../bitacross/core/bc-relayer-registry", default-features = false, features = ["sgx"] } bc-signer-registry = { path = "../bitacross/core/bc-signer-registry", default-features = false, features = ["sgx"] } bc-task-sender = { path = "../bitacross/core/bc-task-sender", default-features = false, features = ["sgx"] } -lc-scheduled-enclave = { path = "../litentry/core/scheduled-enclave", default-features = false, features = ["sgx"] } +lc-direct-call = { path = "../litentry/core/direct-call", default-features = false } litentry-hex-utils = { path = "../../primitives/hex", default-features = false } litentry-macros = { path = "../../primitives/core/macros", default-features = false } litentry-primitives = { path = "../litentry/primitives", default-features = false, features = ["sgx"] } diff --git a/bitacross-worker/enclave-runtime/Enclave.edl b/bitacross-worker/enclave-runtime/Enclave.edl index 5f0dc05928..b0b0b64e7f 100644 --- a/bitacross-worker/enclave-runtime/Enclave.edl +++ b/bitacross-worker/enclave-runtime/Enclave.edl @@ -173,11 +173,10 @@ enclave { public size_t test_main_entrance(); public sgx_status_t migrate_shard( - [in, size=shard_size] uint8_t* old_shard, - [in, size=shard_size] uint8_t* new_shard, + [in, size=shard_size] uint8_t* new_shard, uint32_t shard_size ); - + public sgx_status_t ignore_parentchain_block_import_validation_until( [in] uint32_t* until ); diff --git a/bitacross-worker/enclave-runtime/src/attestation.rs b/bitacross-worker/enclave-runtime/src/attestation.rs index a213babf04..732f6d2851 100644 --- a/bitacross-worker/enclave-runtime/src/attestation.rs +++ b/bitacross-worker/enclave-runtime/src/attestation.rs @@ -51,7 +51,7 @@ use itp_settings::worker::MR_ENCLAVE_SIZE; use itp_sgx_crypto::{ ed25519_derivation::DeriveEd25519, key_repository::AccessKey, Error as SgxCryptoError, }; -use itp_types::{AttestationType, OpaqueCall, WorkerType}; +use itp_types::{AttestationType, DcapProvider, OpaqueCall, WorkerType}; use itp_utils::write_slice_and_whitespace_pad; use litentry_primitives::WorkerMode; use log::*; @@ -328,7 +328,7 @@ pub fn generate_dcap_ra_extrinsic_from_quote_internal( let shielding_pubkey = get_shielding_pubkey()?; let vc_pubkey = get_vc_pubkey()?; - let attestation_type = AttestationType::Dcap(Default::default()); // skip_ra should be false here already + let attestation_type = AttestationType::Dcap(DcapProvider::Intel); // skip_ra should be false here already let call = OpaqueCall::from_tuple(&( call_ids, diff --git a/bitacross-worker/enclave-runtime/src/initialization/mod.rs b/bitacross-worker/enclave-runtime/src/initialization/mod.rs index 06f09cdc29..6c401a78f2 100644 --- a/bitacross-worker/enclave-runtime/src/initialization/mod.rs +++ b/bitacross-worker/enclave-runtime/src/initialization/mod.rs @@ -65,7 +65,7 @@ use itc_tls_websocket_server::{ config_provider::FromFileConfigProvider, ws_server::TungsteniteWsServer, ConnectionToken, WebSocketServer, }; -use itp_attestation_handler::{AttestationHandler, IntelAttestationHandler}; +use itp_attestation_handler::IntelAttestationHandler; use itp_component_container::{ComponentGetter, ComponentInitializer}; use itp_extrinsics_factory::CreateExtrinsics; use itp_node_api_metadata::pallet_bitacross::BitAcrossCallIndexes; @@ -95,7 +95,6 @@ use itp_stf_state_handler::{ use itp_top_pool::pool::Options as PoolOptions; use itp_top_pool_author::author::AuthorTopFilter; use itp_types::{parentchain::ParentchainId, OpaqueCall, ShardIdentifier}; -use lc_scheduled_enclave::{ScheduledEnclaveUpdater, GLOBAL_SCHEDULED_ENCLAVE}; use litentry_macros::if_development_or; use log::*; use sp_core::crypto::Pair; @@ -276,10 +275,8 @@ pub(crate) fn init_enclave( } pub(crate) fn finish_enclave_init() -> EnclaveResult<()> { - let attestation_handler = GLOBAL_ATTESTATION_HANDLER_COMPONENT.get()?; - let mrenclave = attestation_handler.get_mrenclave()?; - GLOBAL_SCHEDULED_ENCLAVE.init(mrenclave).map_err(|e| Error::Other(e.into()))?; - + // TODO: it's not required after ScheduledEnclave is removed + // however, it's not bad to leave a placeholder as post-init hook Ok(()) } @@ -351,11 +348,6 @@ pub(crate) fn publish_wallets() -> EnclaveResult<()> { .execute_mut_on_validator(|v| v.send_extrinsics(xts)) .map_err(|e| Error::Other(e.into()))?; - //todo: this should be called as late as possible P-727 - let attestation_handler = GLOBAL_ATTESTATION_HANDLER_COMPONENT.get()?; - let mrenclave = attestation_handler.get_mrenclave()?; - GLOBAL_SCHEDULED_ENCLAVE.init(mrenclave).map_err(|e| Error::Other(e.into()))?; - Ok(()) } @@ -461,12 +453,9 @@ pub(crate) fn init_shard(shard: ShardIdentifier) -> EnclaveResult<()> { Ok(()) } -pub(crate) fn migrate_shard( - old_shard: ShardIdentifier, - new_shard: ShardIdentifier, -) -> EnclaveResult<()> { +pub(crate) fn migrate_shard(new_shard: ShardIdentifier) -> EnclaveResult<()> { let state_handler = GLOBAL_STATE_HANDLER_COMPONENT.get()?; - let _ = state_handler.migrate_shard(old_shard, new_shard)?; + let _ = state_handler.migrate_shard(new_shard)?; Ok(()) } diff --git a/bitacross-worker/enclave-runtime/src/lib.rs b/bitacross-worker/enclave-runtime/src/lib.rs index 0205ff3aca..c0b49ad5c2 100644 --- a/bitacross-worker/enclave-runtime/src/lib.rs +++ b/bitacross-worker/enclave-runtime/src/lib.rs @@ -505,19 +505,12 @@ pub unsafe extern "C" fn init_shard(shard: *const u8, shard_size: u32) -> sgx_st } #[no_mangle] -pub unsafe extern "C" fn migrate_shard( - old_shard: *const u8, - new_shard: *const u8, - shard_size: u32, -) -> sgx_status_t { - let old_shard_identifier = - ShardIdentifier::from_slice(slice::from_raw_parts(old_shard, shard_size as usize)); - - let new_shard_identifier = +pub unsafe extern "C" fn migrate_shard(new_shard: *const u8, shard_size: u32) -> sgx_status_t { + let shard_identifier = ShardIdentifier::from_slice(slice::from_raw_parts(new_shard, shard_size as usize)); - if let Err(e) = initialization::migrate_shard(old_shard_identifier, new_shard_identifier) { - error!("Failed to initialize shard ({:?}): {:?}", old_shard_identifier, e); + if let Err(e) = initialization::migrate_shard(shard_identifier) { + error!("Failed to migrate shard ({:?}): {:?}", shard_identifier, e); return sgx_status_t::SGX_ERROR_UNEXPECTED } diff --git a/bitacross-worker/enclave-runtime/src/rpc/worker_api_direct.rs b/bitacross-worker/enclave-runtime/src/rpc/worker_api_direct.rs index c700c0466e..3128077783 100644 --- a/bitacross-worker/enclave-runtime/src/rpc/worker_api_direct.rs +++ b/bitacross-worker/enclave-runtime/src/rpc/worker_api_direct.rs @@ -44,20 +44,18 @@ use itp_sgx_crypto::{ ShieldingCryptoDecrypt, ShieldingCryptoEncrypt, }; use itp_stf_executor::getter_executor::ExecuteGetter; +use itp_stf_primitives::types::KeyPair; use itp_top_pool_author::traits::AuthorApi; use itp_types::{DirectRequestStatus, RsaRequest, ShardIdentifier, H256}; use itp_utils::{FromHexPrefixed, ToHexPrefixed}; use jsonrpc_core::{serde_json::json, IoHandler, Params, Value}; -#[cfg(feature = "development")] -use lc_scheduled_enclave::ScheduledEnclaveUpdater; -use lc_scheduled_enclave::GLOBAL_SCHEDULED_ENCLAVE; -use litentry_macros::if_development; -use litentry_primitives::{AesRequest, DecryptableRequest}; +use lc_direct_call::DirectCall; +use litentry_primitives::{aes_encrypt_default, AesRequest, DecryptableRequest, Identity}; use log::{debug, error}; use sgx_crypto_helper::rsa3072::Rsa3072PubKey; use sp_core::crypto::Pair; use sp_runtime::OpaqueExtrinsic; -use std::{borrow::ToOwned, format, str, string::String, sync::Arc, vec::Vec}; +use std::{borrow::ToOwned, boxed::Box, format, str, string::String, sync::Arc, vec::Vec}; fn compute_hex_encoded_return_error(error_msg: &str) -> String { RpcReturnValue::from_error_message(error_msg).to_hex() @@ -97,6 +95,9 @@ where let signer_lookup_cloned = signer_lookup.clone(); let shielding_key_cloned = shielding_key.clone(); + let shielding_key_cloned_2 = shielding_key.clone(); + let signing_key_repository_cloned = signing_key_repository.clone(); + let ocall_api_cloned = ocall_api.clone(); io.add_sync_method("author_getShieldingKey", move |_: Params| { debug!("worker_api_direct rpc was called: author_getShieldingKey"); let rsa_pubkey = match shielding_key_cloned.retrieve_pubkey() { @@ -161,6 +162,37 @@ where } }); + io.add_method("bitacross_checkSignBitcoin", move |_params: Params| { + debug!("worker_api_direct rpc was called: bitacross_checkSignBitcoin"); + let request = prepare_check_sign_bitcoin_request( + signing_key_repository_cloned.as_ref(), + shielding_key_cloned_2.as_ref(), + ocall_api_cloned.as_ref(), + ); + async move { + if let Ok(request) = request { + let params = Params::Array(vec![jsonrpc_core::Value::String(request.to_hex())]); + let json_value = match request_bit_across_inner(params).await { + Ok(value) => value.to_hex(), + Err(error) => RpcReturnValue { + value: error, + do_watch: false, + status: DirectRequestStatus::Error, + } + .to_hex(), + }; + Ok(json!(json_value)) + } else { + Ok(json!(RpcReturnValue { + value: vec![], + do_watch: false, + status: DirectRequestStatus::Error, + } + .to_hex())) + } + } + }); + io.add_sync_method("bitacross_aggregatedPublicKey", move |_: Params| { debug!("worker_api_direct rpc was called: bitacross_aggregatedPublicKey"); if let Ok(keys) = signer_lookup @@ -218,22 +250,6 @@ where Ok(json!(keys)) }); - io.add_sync_method("state_getScheduledEnclave", move |_: Params| { - debug!("worker_api_direct rpc was called: state_getScheduledEnclave"); - let json_value = match GLOBAL_SCHEDULED_ENCLAVE.registry.read() { - Ok(registry) => { - let mut serialized_registry = vec![]; - for (block_number, mrenclave) in registry.iter() { - serialized_registry.push((*block_number, *mrenclave)); - } - RpcReturnValue::new(serialized_registry.encode(), false, DirectRequestStatus::Ok) - .to_hex() - }, - Err(_err) => compute_hex_encoded_return_error("Poisoned registry storage"), - }; - Ok(json!(json_value)) - }); - io.add_sync_method("author_getShard", move |_: Params| { debug!("worker_api_direct rpc was called: author_getShard"); let shard = top_pool_author.list_handled_shards().first().copied().unwrap_or_default(); @@ -348,46 +364,6 @@ where Ok(json!(json_value)) }); - if_development!({ - use itp_types::{MrEnclave, SidechainBlockNumber}; - // state_setScheduledEnclave, params: sidechainBlockNumber, hex encoded mrenclave - io.add_sync_method("state_setScheduledEnclave", move |params: Params| { - match params.parse::<(SidechainBlockNumber, String)>() { - Ok((bn, mrenclave)) => - return match hex::decode(&mrenclave) { - Ok(mrenclave) => { - let mut enclave_to_set: MrEnclave = [0u8; 32]; - if mrenclave.len() != enclave_to_set.len() { - return Ok(json!(compute_hex_encoded_return_error( - "mrenclave len mismatch, expected 32 bytes long" - ))) - } - - enclave_to_set.copy_from_slice(&mrenclave); - return match GLOBAL_SCHEDULED_ENCLAVE.update(bn, enclave_to_set) { - Ok(()) => Ok(json!(RpcReturnValue::new( - vec![], - false, - DirectRequestStatus::Ok - ) - .to_hex())), - Err(e) => { - let error_msg = - format!("Failed to set scheduled mrenclave {:?}", e); - Ok(json!(compute_hex_encoded_return_error(error_msg.as_str()))) - }, - } - }, - Err(e) => { - let error_msg = format!("Failed to decode mrenclave {:?}", e); - Ok(json!(compute_hex_encoded_return_error(error_msg.as_str()))) - }, - }, - Err(_) => Ok(json!(compute_hex_encoded_return_error("parse error"))), - } - }); - }); - // system_health io.add_sync_method("system_health", |_: Params| { debug!("worker_api_direct rpc was called: system_health"); @@ -416,6 +392,35 @@ where io } +fn prepare_check_sign_bitcoin_request( + signing_key_repository: &EnclaveSigningKeyRepository, + shielding_key: &AccessShieldingKey, + ocall_api: &OcallApi, +) -> Result +where + AccessShieldingKey: AccessPubkey + AccessKey + Send + Sync + 'static, + ::KeyType: + ShieldingCryptoDecrypt + ShieldingCryptoEncrypt + DeriveEd25519 + Send + Sync + 'static, + OcallApi: EnclaveAttestationOCallApi + Send + Sync + 'static, +{ + let aes_key = [0u8; 32]; + let signer = signing_key_repository.retrieve_key().map_err(|_| ())?; + let shielding_key = shielding_key.retrieve_pubkey().map_err(|_| ())?; + let identity = Identity::Substrate(signer.public().into()); + let mrenclave = ocall_api.get_mrenclave_of_self().map_err(|_| ())?.m; + let call = DirectCall::CheckSignBitcoin(identity).sign( + &KeyPair::Ed25519(Box::new(signer)), + &mrenclave, + &mrenclave.into(), + ); + let encrypted = aes_encrypt_default(&aes_key, &call.encode()); + Ok(AesRequest { + shard: mrenclave.into(), + key: shielding_key.encrypt(&aes_key).map_err(|_| ())?, + payload: encrypted, + }) +} + // Litentry: TODO - we still use `RsaRequest` for trusted getter, as the result // in unencrypted, see P-183 fn execute_getter_inner( diff --git a/bitacross-worker/litentry/core/direct-call/src/handler/sign_bitcoin.rs b/bitacross-worker/litentry/core/direct-call/src/handler/sign_bitcoin.rs index 3d3c3cfa10..c0b673b3bb 100644 --- a/bitacross-worker/litentry/core/direct-call/src/handler/sign_bitcoin.rs +++ b/bitacross-worker/litentry/core/direct-call/src/handler/sign_bitcoin.rs @@ -30,6 +30,7 @@ use bc_musig2_ceremony::{ use bc_signer_registry::SignerRegistryLookup; use itp_sgx_crypto::schnorr::Pair as SchnorrPair; +use bc_enclave_registry::EnclaveRegistryLookup; use bc_musig2_ceremony::SignBitcoinPayload; #[cfg(feature = "sgx")] use std::sync::SgxMutex as Mutex; @@ -39,18 +40,26 @@ pub fn handle< RRL: RelayerRegistryLookup, SR: SignerRegistryLookup, AK: AccessKey, + ER: EnclaveRegistryLookup, >( signer: Identity, payload: SignBitcoinPayload, aes_key: [u8; 32], + check_run: bool, relayer_registry: &RRL, ceremony_registry: Arc>>, ceremony_commands: Arc>, signer_registry: Arc, + enclave_registry: &ER, enclave_key_pub: &[u8; 32], signer_access_key: Arc, ) -> Result<(), SignBitcoinError> { - if relayer_registry.contains_key(signer) { + //sign bitcoin can come from two trusted sources - authorized relayers or any registered enclave + if relayer_registry.contains_key(&signer) + || match &signer { + Identity::Substrate(address) => enclave_registry.contains_key(address), + _ => false, + } { let mut registry = ceremony_registry.lock().map_err(|_| SignBitcoinError::CeremonyError)?; // ~1 minute (1 tick ~ 1 ms) let ceremony_tick_to_live = 60_000; @@ -82,6 +91,7 @@ pub fn handle< pending_commands.into_iter().map(|c| c.command).collect(), signer_access_key, ceremony_tick_to_live, + check_run, ) .map_err(|e| { error!("Could not start ceremony, error: {:?}", e); @@ -99,6 +109,7 @@ pub fn handle< pub mod test { use crate::handler::sign_bitcoin::{handle, SignBitcoinError}; use alloc::sync::Arc; + use bc_enclave_registry::{EnclaveRegistry, EnclaveRegistryUpdater}; use bc_musig2_ceremony::{CeremonyCommandsRegistry, CeremonyRegistry, SignBitcoinPayload}; use bc_relayer_registry::{RelayerRegistry, RelayerRegistryUpdater}; use bc_signer_registry::{PubKey, SignerRegistryLookup}; @@ -155,6 +166,7 @@ pub mod test { pub fn it_should_return_ok_for_relayer_signer() { // given let relayer_registry = RelayerRegistry::default(); + let enclave_registry = EnclaveRegistry::default(); let alice_key_pair = sr25519::Pair::from_string("//Alice", None).unwrap(); let relayer_account = Identity::Substrate(alice_key_pair.public().into()); relayer_registry.update(relayer_account.clone()).unwrap(); @@ -168,10 +180,12 @@ pub mod test { relayer_account, SignBitcoinPayload::Derived(vec![]), [0u8; 32], + false, &relayer_registry, ceremony_registry, ceremony_commands_registry, signers_registry, + &enclave_registry, &[0u8; 32], signer_access_key, ); @@ -181,9 +195,43 @@ pub mod test { } #[test] - pub fn it_should_return_err_for_non_relayer_signer() { + pub fn it_should_return_ok_for_enclave_signer() { + // given + let relayer_registry = RelayerRegistry::default(); + let mut enclave_registry = EnclaveRegistry::default(); + let alice_key_pair = sr25519::Pair::from_string("//Alice", None).unwrap(); + let enclave_account = Identity::Substrate(alice_key_pair.public().into()); + enclave_registry.update(alice_key_pair.public().into(), "".to_string()).unwrap(); + let ceremony_registry = Arc::new(Mutex::new(CeremonyRegistry::new())); + let ceremony_commands_registry = Arc::new(Mutex::new(CeremonyCommandsRegistry::new())); + let signers_registry = Arc::new(SignersRegistryMock {}); + let signer_access_key = Arc::new(SignerAccess {}); + + // when + let result = handle( + enclave_account, + SignBitcoinPayload::Derived(vec![]), + [0u8; 32], + false, + &relayer_registry, + ceremony_registry, + ceremony_commands_registry, + signers_registry, + &enclave_registry, + &[0u8; 32], + signer_access_key, + ); + + // then + assert!(result.is_ok()) + } + + #[test] + pub fn it_should_return_err_for_non_relayer_and_non_enclave_signer() { //given let relayer_registry = RelayerRegistry::default(); + let enclave_registry = EnclaveRegistry::default(); + let alice_key_pair = sr25519::Pair::from_string("//Alice", None).unwrap(); let non_relayer_account = Identity::Substrate(alice_key_pair.public().into()); let ceremony_registry = Arc::new(Mutex::new(CeremonyRegistry::new())); @@ -196,10 +244,12 @@ pub mod test { non_relayer_account, SignBitcoinPayload::Derived(vec![]), [0u8; 32], + false, &relayer_registry, ceremony_registry, ceremony_commands_registry, signers_registry, + &enclave_registry, &alice_key_pair.public().0, signer_access_key, ); @@ -212,6 +262,7 @@ pub mod test { pub fn it_should_return_err_for_existing_ceremony() { // given let relayer_registry = RelayerRegistry::default(); + let enclave_registry = EnclaveRegistry::default(); let alice_key_pair = sr25519::Pair::from_string("//Alice", None).unwrap(); let relayer_account = Identity::Substrate(alice_key_pair.public().into()); relayer_registry.update(relayer_account.clone()).unwrap(); @@ -225,10 +276,12 @@ pub mod test { relayer_account.clone(), SignBitcoinPayload::Derived(vec![]), [0u8; 32], + false, &relayer_registry, ceremony_registry.clone(), ceremony_commands_registry.clone(), signers_registry.clone(), + &enclave_registry, &[0u8; 32], signer_access_key.clone(), ) @@ -238,10 +291,12 @@ pub mod test { relayer_account, SignBitcoinPayload::Derived(vec![]), [0u8; 32], + false, &relayer_registry, ceremony_registry, ceremony_commands_registry, signers_registry, + &enclave_registry, &[0u8; 32], signer_access_key, ); diff --git a/bitacross-worker/litentry/core/direct-call/src/handler/sign_ethereum.rs b/bitacross-worker/litentry/core/direct-call/src/handler/sign_ethereum.rs index 677223a333..fa0fbf52fc 100644 --- a/bitacross-worker/litentry/core/direct-call/src/handler/sign_ethereum.rs +++ b/bitacross-worker/litentry/core/direct-call/src/handler/sign_ethereum.rs @@ -33,7 +33,7 @@ pub fn handle>( relayer_registry: &RRL, key_repository: &EKR, ) -> Result<[u8; 65], SignEthereumError> { - if relayer_registry.contains_key(signer) { + if relayer_registry.contains_key(&signer) { let key = key_repository.retrieve_key().map_err(|e| { error!("Could not retrieve ethereum signing key: {}", e); SignEthereumError::SigningError diff --git a/bitacross-worker/litentry/core/direct-call/src/lib.rs b/bitacross-worker/litentry/core/direct-call/src/lib.rs index 1eb561e8a2..938b4d6c0f 100644 --- a/bitacross-worker/litentry/core/direct-call/src/lib.rs +++ b/bitacross-worker/litentry/core/direct-call/src/lib.rs @@ -54,6 +54,7 @@ pub enum DirectCall { NonceShare(Identity, RequestAesKey, SignBitcoinPayload, [u8; 66]), PartialSignatureShare(Identity, RequestAesKey, SignBitcoinPayload, [u8; 32]), KillCeremony(Identity, RequestAesKey, SignBitcoinPayload), + CheckSignBitcoin(Identity), } impl DirectCall { @@ -64,6 +65,7 @@ impl DirectCall { Self::NonceShare(signer, ..) => signer, Self::PartialSignatureShare(signer, ..) => signer, Self::KillCeremony(signer, ..) => signer, + Self::CheckSignBitcoin(signer) => signer, } } diff --git a/bitacross-worker/litentry/core/scheduled-enclave/Cargo.toml b/bitacross-worker/litentry/core/scheduled-enclave/Cargo.toml deleted file mode 100644 index 8e6f1904e7..0000000000 --- a/bitacross-worker/litentry/core/scheduled-enclave/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "lc-scheduled-enclave" -version = "0.8.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -codec = { version = "3.0.0", default-features = false, features = ["derive"], package = "parity-scale-codec" } -lazy_static = { version = "1.1.0", features = ["spin_no_std"] } -log = { version = "0.4", default-features = false } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } -thiserror = { version = "1.0.26", optional = true } - -# sgx-deps -sgx_tstd = { branch = "master", git = "https://github.com/apache/teaclave-sgx-sdk.git", features = ["untrusted_fs"], optional = true } -thiserror-sgx = { package = "thiserror", git = "https://github.com/mesalock-linux/thiserror-sgx", tag = "sgx_1.1.3", optional = true } - -# local dependencies -itp-settings = { path = "../../../core-primitives/settings" } -itp-sgx-io = { path = "../../../core-primitives/sgx/io", default-features = false } -itp-types = { path = "../../../core-primitives/types", default-features = false } - -[features] -default = ["std"] -sgx = [ - "sgx_tstd", - "thiserror-sgx", - "itp-sgx-io/sgx", -] -std = [ - "thiserror", - "itp-sgx-io/std", - "itp-types/std", - "sp-std/std", - "codec/std", -] diff --git a/bitacross-worker/litentry/core/scheduled-enclave/src/error.rs b/bitacross-worker/litentry/core/scheduled-enclave/src/error.rs deleted file mode 100644 index 70228b33a0..0000000000 --- a/bitacross-worker/litentry/core/scheduled-enclave/src/error.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2020-2024 Trust Computing GmbH. -// This file is part of Litentry. -// -// Litentry is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Litentry is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Litentry. If not, see . - -use std::boxed::Box; -#[cfg(feature = "sgx")] -use thiserror_sgx as thiserror; - -pub type Result = core::result::Result; - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("poison lock")] - PoisonLock, - #[error("empty ScheduledEnclave registry")] - EmptyRegistry, - #[error("no previous MRENCLAVE")] - NoPreviousMRENCLAVE, - #[error(transparent)] - Other(#[from] Box), -} - -impl From for Error { - fn from(e: std::io::Error) -> Self { - Self::Other(e.into()) - } -} - -impl From for Error { - #[cfg(feature = "std")] - fn from(e: codec::Error) -> Self { - Self::Other(e.into()) - } - - #[cfg(feature = "sgx")] - fn from(e: codec::Error) -> Self { - Self::Other(std::format!("{:?}", e).into()) - } -} diff --git a/bitacross-worker/litentry/core/scheduled-enclave/src/io.rs b/bitacross-worker/litentry/core/scheduled-enclave/src/io.rs deleted file mode 100644 index 7aad2bc57d..0000000000 --- a/bitacross-worker/litentry/core/scheduled-enclave/src/io.rs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2020-2024 Trust Computing GmbH. -// This file is part of Litentry. -// -// Litentry is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Litentry is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Litentry. If not, see . - -#[cfg(all(feature = "std", feature = "sgx"))] -compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the same time"); - -use crate::{ - error::{Error, Result}, - MrEnclave, ScheduledEnclave, ScheduledEnclaveUpdater, SidechainBlockNumber, - GLOBAL_SCHEDULED_ENCLAVE, -}; - -#[cfg(feature = "sgx")] -mod sgx { - use crate::{ - error::{Error, Result}, - ScheduledEnclaveMap, - }; - pub use codec::{Decode, Encode}; - pub use itp_settings::files::SCHEDULED_ENCLAVE_FILE; - pub use itp_sgx_io::{seal, unseal, SealedIO}; - pub use log::*; - pub use std::{boxed::Box, fs, path::PathBuf, sgxfs::SgxFile, sync::Arc}; - - #[derive(Clone, Debug)] - pub struct ScheduledEnclaveSeal { - base_path: PathBuf, - } - - impl ScheduledEnclaveSeal { - pub fn new(base_path: PathBuf) -> Self { - Self { base_path } - } - - pub fn path(&self) -> PathBuf { - self.base_path.join(SCHEDULED_ENCLAVE_FILE) - } - } - - impl SealedIO for ScheduledEnclaveSeal { - type Error = Error; - type Unsealed = ScheduledEnclaveMap; - - fn unseal(&self) -> Result { - Ok(unseal(self.path()).map(|b| Decode::decode(&mut b.as_slice()))??) - } - - fn seal(&self, unsealed: &Self::Unsealed) -> Result<()> { - info!("Seal scheduled enclave to file: {:?}", unsealed); - Ok(unsealed.using_encoded(|bytes| seal(bytes, self.path()))?) - } - } -} - -#[cfg(feature = "sgx")] -use sgx::*; - -// TODO: unit-test -impl ScheduledEnclaveUpdater for ScheduledEnclave { - #[cfg(feature = "std")] - fn init(&self, _mrenclave: MrEnclave) -> Result<()> { - Ok(()) - } - - #[cfg(feature = "std")] - fn update(&self, _sbn: SidechainBlockNumber, _mrenclave: MrEnclave) -> Result<()> { - Ok(()) - } - - #[cfg(feature = "std")] - fn remove(&self, _sbn: SidechainBlockNumber) -> Result<()> { - Ok(()) - } - - // if `SCHEDULED_ENCLAVE_FILE` exists, unseal and init from it - // otherwise create a new instance and seal to static file - #[cfg(feature = "sgx")] - fn init(&self, mrenclave: MrEnclave) -> Result<()> { - let _ = self.set_current_mrenclave(mrenclave)?; - let _ = self.set_block_production_paused(false)?; - let enclave_seal = ScheduledEnclaveSeal::new(self.seal_path.clone()); - if SgxFile::open(SCHEDULED_ENCLAVE_FILE).is_err() { - info!( - "[Enclave] ScheduledEnclave file not found, creating new! {}", - SCHEDULED_ENCLAVE_FILE - ); - let mut registry = - GLOBAL_SCHEDULED_ENCLAVE.registry.write().map_err(|_| Error::PoisonLock)?; - registry.clear(); - registry.insert(0, mrenclave); - enclave_seal.seal(&*registry) - } else { - let m = enclave_seal.unseal()?; - info!("[Enclave] ScheduledEnclave unsealed from file: {:?}", m); - let mut registry = - GLOBAL_SCHEDULED_ENCLAVE.registry.write().map_err(|_| Error::PoisonLock)?; - *registry = m; - Ok(()) - } - } - - #[cfg(feature = "sgx")] - fn update(&self, sbn: SidechainBlockNumber, mrenclave: MrEnclave) -> Result<()> { - let mut registry = - GLOBAL_SCHEDULED_ENCLAVE.registry.write().map_err(|_| Error::PoisonLock)?; - registry.insert(sbn, mrenclave); - ScheduledEnclaveSeal::new(self.seal_path.clone()).seal(&*registry) - } - - #[cfg(feature = "sgx")] - fn remove(&self, sbn: SidechainBlockNumber) -> Result<()> { - let mut registry = - GLOBAL_SCHEDULED_ENCLAVE.registry.write().map_err(|_| Error::PoisonLock)?; - let old_value = registry.remove(&sbn); - if old_value.is_some() { - return ScheduledEnclaveSeal::new(self.seal_path.clone()).seal(&*registry) - } - Ok(()) - } - - fn get_current_mrenclave(&self) -> Result { - self.current_mrenclave.read().map_err(|_| Error::PoisonLock).map(|l| *l) - } - - fn set_current_mrenclave(&self, mrenclave: MrEnclave) -> Result<()> { - let mut m = self.current_mrenclave.write().map_err(|_| Error::PoisonLock)?; - *m = mrenclave; - Ok(()) - } - - fn get_expected_mrenclave(&self, sbn: SidechainBlockNumber) -> Result { - let registry = GLOBAL_SCHEDULED_ENCLAVE.registry.read().map_err(|_| Error::PoisonLock)?; - let r = registry - .iter() - .filter(|(k, _)| **k <= sbn) - .max_by_key(|(k, _)| **k) - .ok_or(Error::EmptyRegistry)?; - Ok(*r.1) - } - - fn get_previous_mrenclave(&self, sbn: SidechainBlockNumber) -> Result { - // TODO: optimise it - let registry = GLOBAL_SCHEDULED_ENCLAVE.registry.read().map_err(|_| Error::PoisonLock)?; - let r = registry - .iter() - .filter(|(k, _)| **k <= sbn) - .max_by_key(|(k, _)| **k) - .ok_or(Error::NoPreviousMRENCLAVE)?; - let v = registry - .iter() - .filter(|(k, _)| **k < *r.0) - .max_by_key(|(k, _)| **k) - .ok_or(Error::NoPreviousMRENCLAVE)?; - Ok(*v.1) - } - - fn is_block_production_paused(&self) -> Result { - self.block_production_paused.read().map_err(|_| Error::PoisonLock).map(|l| *l) - } - - fn set_block_production_paused(&self, should_pause: bool) -> Result<()> { - let mut p = self.block_production_paused.write().map_err(|_| Error::PoisonLock)?; - *p = should_pause; - Ok(()) - } -} diff --git a/bitacross-worker/litentry/core/scheduled-enclave/src/lib.rs b/bitacross-worker/litentry/core/scheduled-enclave/src/lib.rs deleted file mode 100644 index ddb47e2e3d..0000000000 --- a/bitacross-worker/litentry/core/scheduled-enclave/src/lib.rs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2020-2024 Trust Computing GmbH. -// This file is part of Litentry. -// -// Litentry is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Litentry is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Litentry. If not, see . - -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(all(feature = "std", feature = "sgx"))] -compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the same time"); - -#[cfg(feature = "sgx")] -extern crate sgx_tstd as std; - -// TODO: maybe use parachain primitives for single source of truth -use itp_types::{MrEnclave, SidechainBlockNumber}; -use sp_std::collections::btree_map::BTreeMap; -use std::path::PathBuf; - -pub mod error; -use error::Result; -pub mod io; - -#[cfg(feature = "std")] -use std::sync::RwLock; -#[cfg(feature = "sgx")] -use std::sync::SgxRwLock as RwLock; - -use lazy_static::lazy_static; -use std::sync::Arc; - -lazy_static! { - /// Global instance of a ScheduledEnclave - pub static ref GLOBAL_SCHEDULED_ENCLAVE: Arc = Default::default(); -} - -pub type ScheduledEnclaveMap = BTreeMap; - -#[derive(Default)] -pub struct ScheduledEnclave { - pub block_production_paused: RwLock, - pub current_mrenclave: RwLock, - pub registry: RwLock, - pub seal_path: PathBuf, -} - -pub trait ScheduledEnclaveUpdater { - fn init(&self, mrenclave: MrEnclave) -> Result<()>; - - fn update(&self, sbn: SidechainBlockNumber, mrenclave: MrEnclave) -> Result<()>; - - fn remove(&self, sbn: SidechainBlockNumber) -> Result<()>; - - fn get_current_mrenclave(&self) -> Result; - - fn set_current_mrenclave(&self, mrenclave: MrEnclave) -> Result<()>; - - // given a SidechainBlockNumber, return the expected MRENCLAVE - // For example, the registry is: - // 0 -> 0xAA - // 19 -> 0xBB - // 21 -> 0xCC - // - // get_expected_mrenclave(0) -> 0xAA - // get_expected_mrenclave(18) -> 0xAA - // get_expected_mrenclave(19) -> 0xBB - // get_expected_mrenclave(20) -> 0xBB - // get_expected_mrenclave(21) -> 0xCC - // get_expected_mrenclave(30) -> 0xCC - fn get_expected_mrenclave(&self, sbn: SidechainBlockNumber) -> Result; - - // given a SidechainBlockNumber, return the previous MRENCLAVE - // we can't simply use `get_previous_mrenclave(sbn - 1)` due to possible gap - // For example, the registry is: - // 0 -> 0xAA - // 19 -> 0xBB - // 21 -> 0xCC - // - // get_previous_mrenclave(0) -> NoPreviousMRENCLAVE error - // get_previous_mrenclave(1) -> NoPreviousMRENCLAVE error - // get_previous_mrenclave(19) -> 0xAA - // get_previous_mrenclave(20) -> 0xAA - // get_previous_mrenclave(21) -> 0xBB - // get_previous_mrenclave(30) -> 0xBB - fn get_previous_mrenclave(&self, sbn: SidechainBlockNumber) -> Result; - - fn is_block_production_paused(&self) -> Result; - - fn set_block_production_paused(&self, should_pause: bool) -> Result<()>; - - fn is_mrenclave_matching(&self, sbn: SidechainBlockNumber) -> bool { - let current = self.get_current_mrenclave(); - let expected = self.get_expected_mrenclave(sbn); - - if current.is_err() || expected.is_err() { - return false - } - - current.unwrap() == expected.unwrap() - } -} - -#[derive(Default)] -pub struct ScheduledEnclaveMock; - -// todo! -impl ScheduledEnclaveUpdater for ScheduledEnclaveMock { - fn init(&self, _mrenclave: MrEnclave) -> Result<()> { - Ok(()) - } - - fn update(&self, _sbn: SidechainBlockNumber, _mrenclave: MrEnclave) -> Result<()> { - Ok(()) - } - - fn remove(&self, _sbn: SidechainBlockNumber) -> Result<()> { - Ok(()) - } - - fn get_current_mrenclave(&self) -> Result { - Ok(MrEnclave::default()) - } - - fn set_current_mrenclave(&self, _mrenclave: MrEnclave) -> Result<()> { - Ok(()) - } - - fn get_expected_mrenclave(&self, _sbn: SidechainBlockNumber) -> Result { - Ok(MrEnclave::default()) - } - - fn get_previous_mrenclave(&self, _sbn: SidechainBlockNumber) -> Result { - Ok(MrEnclave::default()) - } - - fn is_block_production_paused(&self) -> Result { - Ok(false) - } - - fn set_block_production_paused(&self, _should_pause: bool) -> Result<()> { - Ok(()) - } -} diff --git a/bitacross-worker/litentry/primitives/src/lib.rs b/bitacross-worker/litentry/primitives/src/lib.rs index b013af90ae..943cd60ea9 100644 --- a/bitacross-worker/litentry/primitives/src/lib.rs +++ b/bitacross-worker/litentry/primitives/src/lib.rs @@ -44,7 +44,7 @@ use itp_sgx_crypto::ShieldingCryptoDecrypt; use litentry_hex_utils::hex_encode; use log::error; pub use pallet_teebag::{ - decl_rsa_request, extract_tcb_info_from_raw_dcap_quote, AttestationType, Enclave, + decl_rsa_request, extract_tcb_info_from_raw_dcap_quote, AttestationType, DcapProvider, Enclave, EnclaveFingerprint, MrEnclave, ShardIdentifier, SidechainBlockNumber, WorkerMode, WorkerType, }; pub use parentchain_primitives::{ diff --git a/bitacross-worker/service/src/cli.yml b/bitacross-worker/service/src/cli.yml index 5a108db9c5..53b1d5184d 100644 --- a/bitacross-worker/service/src/cli.yml +++ b/bitacross-worker/service/src/cli.yml @@ -165,16 +165,7 @@ subcommands: index: 1 help: shard identifier base58 encoded - migrate-shard: - about: Migrate shard - args: - - old-shard: - long: old-shard - help: shard identifier hex encoded - takes_value: true - - new-shard: - long: new-shard - help: shard identifier hex encoded - takes_value: true + about: Migrate state from old shards to the new(current) shard, which is identical to mrenclave - test: about: Run tests involving the enclave takes_value: true diff --git a/bitacross-worker/service/src/config.rs b/bitacross-worker/service/src/config.rs index 8015bee909..97401027f3 100644 --- a/bitacross-worker/service/src/config.rs +++ b/bitacross-worker/service/src/config.rs @@ -17,7 +17,7 @@ use clap::ArgMatches; use itc_rest_client::rest_client::Url; -use itp_types::parentchain::ParentchainId; +use itp_types::{parentchain::ParentchainId, ShardIdentifier}; use parse_duration::parse; use serde::{Deserialize, Serialize}; use std::{ @@ -332,6 +332,7 @@ impl From<&ArgMatches<'_>> for RunConfig { i ), }); + Self { skip_ra, dev, shard, marblerun_base_url, shielding_target } } } diff --git a/bitacross-worker/service/src/enclave/tls_ra.rs b/bitacross-worker/service/src/enclave/tls_ra.rs index 9409b7e39a..318f6a22e8 100644 --- a/bitacross-worker/service/src/enclave/tls_ra.rs +++ b/bitacross-worker/service/src/enclave/tls_ra.rs @@ -83,7 +83,12 @@ pub fn enclave_request_state_provisioning Some(quote_size), Err(e) => return Err(e), @@ -92,7 +97,7 @@ pub fn enclave_request_state_provisioning Some(quote_size), Err(e) => return Err(e), diff --git a/bitacross-worker/service/src/main_impl.rs b/bitacross-worker/service/src/main_impl.rs index 712c93ac42..0f962bf02c 100644 --- a/bitacross-worker/service/src/main_impl.rs +++ b/bitacross-worker/service/src/main_impl.rs @@ -208,7 +208,10 @@ pub(crate) fn main() { enclave.dump_dcap_ra_cert_to_disk().unwrap(); } } else if matches.is_present("mrenclave") { - println!("{}", enclave.get_fingerprint().unwrap().encode().to_base58()); + let mrenclave = enclave.get_fingerprint().unwrap(); + let hex_value = hex::encode(mrenclave); + println!("MRENCLAVE hex: {}", hex_value); + println!("MRENCLAVE base58: {}", mrenclave.encode().to_base58()); } else if let Some(sub_matches) = matches.subcommand_matches("init-shard") { setup::init_shard( enclave.as_ref(), @@ -242,32 +245,10 @@ pub(crate) fn main() { tests::run_enclave_tests(sub_matches); } } else if let Some(sub_matches) = matches.subcommand_matches("migrate-shard") { - // This subcommand `migrate-shard` is only used for manual testing. Maybe deleted later. - let old_shard = sub_matches - .value_of("old-shard") - .map(|value| { - let mut shard = [0u8; 32]; - hex::decode_to_slice(value, &mut shard) - .expect("shard must be hex encoded without 0x"); - ShardIdentifier::from_slice(&shard) - }) - .unwrap(); - - let new_shard: ShardIdentifier = sub_matches - .value_of("new-shard") - .map(|value| { - let mut shard = [0u8; 32]; - hex::decode_to_slice(value, &mut shard) - .expect("shard must be hex encoded without 0x"); - ShardIdentifier::from_slice(&shard) - }) - .unwrap(); - - if old_shard == new_shard { - println!("old_shard should not be the same as new_shard"); - } else { - setup::migrate_shard(enclave.as_ref(), &old_shard, &new_shard); - } + let new_shard = extract_shard(None, enclave.as_ref()); + setup::migrate_shard(enclave.as_ref(), &new_shard); + let new_shard_name = new_shard.encode().to_base58(); + setup::remove_old_shards(config.data_dir(), &new_shard_name); } else if let Some(sub_matches) = matches.subcommand_matches("wallet") { println!("Bitcoin wallet:"); let bitcoin_keypair = enclave.get_bitcoin_wallet_pair().unwrap(); diff --git a/bitacross-worker/service/src/ocall_bridge/bridge_api.rs b/bitacross-worker/service/src/ocall_bridge/bridge_api.rs index 085b9b9fb4..08a3dabad3 100644 --- a/bitacross-worker/service/src/ocall_bridge/bridge_api.rs +++ b/bitacross-worker/service/src/ocall_bridge/bridge_api.rs @@ -43,7 +43,7 @@ pub struct Bridge; impl Bridge { pub fn get_ra_api() -> Arc { - debug!("Requesting RemoteAttestation OCall API instance"); + trace!("Requesting RemoteAttestation OCall API instance"); COMPONENT_FACTORY .read() @@ -53,7 +53,7 @@ impl Bridge { } pub fn get_oc_api() -> Arc { - debug!("Requesting WorkerOnChain OCall API instance"); + trace!("Requesting WorkerOnChain OCall API instance"); COMPONENT_FACTORY .read() @@ -63,7 +63,7 @@ impl Bridge { } pub fn get_ipfs_api() -> Arc { - debug!("Requesting IPFS OCall API instance"); + trace!("Requesting IPFS OCall API instance"); COMPONENT_FACTORY .read() @@ -81,7 +81,7 @@ impl Bridge { } pub fn initialize(component_factory: Arc) { - debug!("Initializing OCall bridge with component factory"); + trace!("Initializing OCall bridge with component factory"); *COMPONENT_FACTORY.write() = Some(component_factory); } diff --git a/bitacross-worker/service/src/ocall_bridge/worker_on_chain_ocall.rs b/bitacross-worker/service/src/ocall_bridge/worker_on_chain_ocall.rs index 5bf574a57b..3e1b181b78 100644 --- a/bitacross-worker/service/src/ocall_bridge/worker_on_chain_ocall.rs +++ b/bitacross-worker/service/src/ocall_bridge/worker_on_chain_ocall.rs @@ -83,7 +83,7 @@ where request: Vec, parentchain_id: Vec, ) -> OCallBridgeResult> { - debug!(" Entering ocall_worker_request"); + trace!(" Entering ocall_worker_request"); let requests: Vec = Decode::decode(&mut request.as_slice())?; if requests.is_empty() { diff --git a/bitacross-worker/service/src/parentchain_handler.rs b/bitacross-worker/service/src/parentchain_handler.rs index 41cfd13515..ca1557cb33 100644 --- a/bitacross-worker/service/src/parentchain_handler.rs +++ b/bitacross-worker/service/src/parentchain_handler.rs @@ -290,7 +290,7 @@ where .expect("Can decode previously encoded header; qed"); start_block = until_synced_header.number + 1; - println!( + info!( "[{:?}] Synced {} out of {} finalized parentchain blocks", id, until_synced_header.number, curr_block_number, ); @@ -321,7 +321,7 @@ where shard, true, )?; - println!("[{:?}] synced block number: #{}", id, last_synced_header.number); + info!("[{:?}] synced block number: #{}", id, last_synced_header.number); std::thread::sleep(std::time::Duration::from_secs(1)); } Ok(last_synced_header) diff --git a/bitacross-worker/service/src/setup.rs b/bitacross-worker/service/src/setup.rs index 93d5fab8b6..94548b7bd8 100644 --- a/bitacross-worker/service/src/setup.rs +++ b/bitacross-worker/service/src/setup.rs @@ -19,8 +19,8 @@ use crate::error::{Error, ServiceResult}; use itp_settings::files::{ ENCLAVE_REGISTRY_FILE, LITENTRY_PARENTCHAIN_LIGHT_CLIENT_DB_PATH, RELAYER_REGISTRY_FILE, - SCHEDULED_ENCLAVE_FILE, SHARDS_PATH, SIGNER_REGISTRY_FILE, - TARGET_A_PARENTCHAIN_LIGHT_CLIENT_DB_PATH, TARGET_B_PARENTCHAIN_LIGHT_CLIENT_DB_PATH, + SHARDS_PATH, SIGNER_REGISTRY_FILE, TARGET_A_PARENTCHAIN_LIGHT_CLIENT_DB_PATH, + TARGET_B_PARENTCHAIN_LIGHT_CLIENT_DB_PATH, }; use std::{fs, path::Path}; @@ -76,23 +76,13 @@ mod needs_enclave { } } - pub(crate) fn migrate_shard( - enclave: &Enclave, - old_shard: &ShardIdentifier, - new_shard: &ShardIdentifier, - ) { - match enclave.migrate_shard(old_shard.encode(), new_shard.encode()) { + pub(crate) fn migrate_shard(enclave: &Enclave, &new_shard: &ShardIdentifier) { + match enclave.migrate_shard(new_shard.encode()) { Err(e) => { - println!( - "Failed to migrate old shard {:?} to new shard{:?}. {:?}", - old_shard, new_shard, e - ); + panic!("Failed to migrate shard {:?}. {:?}", new_shard, e); }, Ok(_) => { - println!( - "Successfully migrate old shard {:?} to new shard{:?}", - old_shard, new_shard - ); + println!("Shard {:?} migrated Successfully", new_shard); }, } } @@ -126,6 +116,17 @@ mod needs_enclave { } } +/// backs up shard directory and restores it after cleaning shards directory +pub(crate) fn remove_old_shards(root_dir: &Path, new_shard_name: &str) { + let shard_backup = root_dir.join("shard_backup"); + let shard_dir = root_dir.join(SHARDS_PATH).join(new_shard_name); + + fs::rename(shard_dir.clone(), shard_backup.clone()).expect("Failed to backup shard"); + remove_dir_if_it_exists(root_dir, SHARDS_PATH).expect("Failed to remove shards directory"); + fs::create_dir_all(root_dir.join(SHARDS_PATH)).expect("Failed to create shards directory"); + fs::rename(shard_backup, shard_dir).expect("Failed to restore shard"); +} + /// Purge all worker files from `dir`. pub(crate) fn purge_files_from_dir(dir: &Path) -> ServiceResult<()> { println!("[+] Performing a clean reset of the worker"); @@ -144,7 +145,6 @@ fn purge_files(root_directory: &Path) -> ServiceResult<()> { remove_dir_if_it_exists(root_directory, TARGET_A_PARENTCHAIN_LIGHT_CLIENT_DB_PATH)?; remove_dir_if_it_exists(root_directory, TARGET_B_PARENTCHAIN_LIGHT_CLIENT_DB_PATH)?; - remove_file_if_it_exists(root_directory, SCHEDULED_ENCLAVE_FILE)?; remove_file_if_it_exists(root_directory, RELAYER_REGISTRY_FILE)?; remove_file_if_it_exists(root_directory, ENCLAVE_REGISTRY_FILE)?; remove_file_if_it_exists(root_directory, SIGNER_REGISTRY_FILE)?; @@ -186,7 +186,6 @@ mod tests { fs::File::create(&shards_path.join("state_1.bin")).unwrap(); fs::File::create(&shards_path.join("state_2.bin")).unwrap(); - fs::File::create(&root_directory.join(SCHEDULED_ENCLAVE_FILE)).unwrap(); fs::File::create(&root_directory.join(RELAYER_REGISTRY_FILE)).unwrap(); fs::File::create(&root_directory.join(ENCLAVE_REGISTRY_FILE)).unwrap(); fs::File::create(&root_directory.join(SIGNER_REGISTRY_FILE)).unwrap(); @@ -204,7 +203,6 @@ mod tests { assert!(!root_directory.join(LITENTRY_PARENTCHAIN_LIGHT_CLIENT_DB_PATH).exists()); assert!(!root_directory.join(TARGET_A_PARENTCHAIN_LIGHT_CLIENT_DB_PATH).exists()); assert!(!root_directory.join(TARGET_B_PARENTCHAIN_LIGHT_CLIENT_DB_PATH).exists()); - assert!(!root_directory.join(SCHEDULED_ENCLAVE_FILE).exists()); assert!(!root_directory.join(RELAYER_REGISTRY_FILE).exists()); assert!(!root_directory.join(ENCLAVE_REGISTRY_FILE).exists()); assert!(!root_directory.join(SIGNER_REGISTRY_FILE).exists()); @@ -220,6 +218,36 @@ mod tests { assert!(purge_files(&root_directory).is_ok()); } + #[test] + fn test_remove_old_shards() { + let test_directory_handle = TestDirectoryHandle::new(PathBuf::from("test_backup_shard")); + let root_directory = test_directory_handle.path(); + let shard_1_name = "test_shard_1"; + let shard_2_name = "test_shard_2"; + + let shard_1_dir = root_directory.join(SHARDS_PATH).join(shard_1_name); + fs::create_dir_all(&shard_1_dir).unwrap(); + fs::File::create(shard_1_dir.join("test_state.bin")).unwrap(); + fs::File::create(shard_1_dir.join("test_state_2.bin")).unwrap(); + + let shard_2_dir = root_directory.join(SHARDS_PATH).join(shard_2_name); + fs::create_dir_all(&shard_2_dir).unwrap(); + fs::File::create(shard_2_dir.join("test_state.bin")).unwrap(); + + assert!(root_directory.join(SHARDS_PATH).join(shard_2_name).exists()); + + remove_old_shards(root_directory, shard_1_name); + + assert!(root_directory.join(SHARDS_PATH).join(shard_1_name).exists()); + assert_eq!( + fs::read_dir(root_directory.join(SHARDS_PATH).join(shard_1_name)) + .expect("Failed to read shard directory") + .count(), + 2 + ); + assert!(!root_directory.join(SHARDS_PATH).join(shard_2_name).exists()); + } + /// Directory handle to automatically initialize a directory /// and upon dropping the reference, removing it again. struct TestDirectoryHandle { diff --git a/bitacross-worker/service/src/tests/mocks/enclave_api_mock.rs b/bitacross-worker/service/src/tests/mocks/enclave_api_mock.rs index c08dd9b1d6..f2b4e17b67 100644 --- a/bitacross-worker/service/src/tests/mocks/enclave_api_mock.rs +++ b/bitacross-worker/service/src/tests/mocks/enclave_api_mock.rs @@ -102,10 +102,6 @@ impl EnclaveBase for EnclaveMock { Ok([1u8; MR_ENCLAVE_SIZE].into()) } - fn migrate_shard(&self, _old_shard: Vec, _new_shard: Vec) -> EnclaveResult<()> { - unimplemented!() - } - fn publish_wallets(&self) -> EnclaveResult<()> { unimplemented!() } @@ -117,6 +113,10 @@ impl EnclaveBase for EnclaveMock { fn init_wallets(&self, _base_dir: &str) -> EnclaveResult<()> { unimplemented!() } + + fn migrate_shard(&self, new_shard: Vec) -> EnclaveResult<()> { + unimplemented!() + } } impl Sidechain for EnclaveMock { diff --git a/local-setup/.env.dev b/local-setup/.env.dev index d5c1b9cf2f..b01024f9f9 100644 --- a/local-setup/.env.dev +++ b/local-setup/.env.dev @@ -61,4 +61,5 @@ MORALIS_API_URL=http://localhost:19527/moralis/ MORALIS_SOLANA_API_URL=http://localhost:19527/moralis_solana/ KARAT_DAO_API_URL=http://localhost:19527/karat_dao/ MAGIC_CRAFT_API_URL=http://localhost:19527/magic_craft/ +DAREN_MARKET_API_URL=http://localhost:19527/daren_market/ BLOCKCHAIN_INFO_API_URL=http://localhost:19527/blockchain_info/ diff --git a/local-setup/py/helpers.py b/local-setup/py/helpers.py index 336535fbde..dbe50bf8e9 100644 --- a/local-setup/py/helpers.py +++ b/local-setup/py/helpers.py @@ -34,7 +34,7 @@ def setup_working_dir(source_dir: str, target_dir: str, worker_bin: str): target_dir: the working directory of the worker to be run. """ - optional = ["key.txt", "spid.txt"] + optional = ["key.txt", "spid.txt", "key_production.txt", "spid_production.txt"] for file in optional: source = f"{source_dir}/{file}" diff --git a/node/res/genesis_info/staging.json b/node/res/genesis_info/staging.json index ba2d6337d3..15864c7f6a 100644 --- a/node/res/genesis_info/staging.json +++ b/node/res/genesis_info/staging.json @@ -31,7 +31,8 @@ ], "developerCommittee": [ "jcRVUU8svEMTtwJjX1HzySNrrVEHVnoAdNAmhnbM8ub5dfbM9", - "jcSQcu5RXtWXKPN78zJogNyqsff1j4ffgoJ2njNcDbZ3qNEh5" + "jcSQcu5RXtWXKPN78zJogNyqsff1j4ffgoJ2njNcDbZ3qNEh5", + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" ], "bootNodes": [ "/dns/parachain-sg-0.staging.litentry.io/tcp/40333/p2p/12D3KooWCnBzJy9w9hQFyiwVG2mADqNaPu3Z6WFThivwnrppdWND" diff --git a/node/src/chain_specs/litentry.rs b/node/src/chain_specs/litentry.rs index 7ebd6bd69f..9590a5dbe7 100644 --- a/node/src/chain_specs/litentry.rs +++ b/node/src/chain_specs/litentry.rs @@ -17,9 +17,10 @@ use super::*; use cumulus_primitives_core::ParaId; use litentry_parachain_runtime::{ - AccountId, AuraId, Balance, BalancesConfig, CouncilMembershipConfig, GenesisConfig, - ParachainInfoConfig, ParachainStakingConfig, PolkadotXcmConfig, SessionConfig, SystemConfig, - TechnicalCommitteeMembershipConfig, UNIT, WASM_BINARY, + AccountId, AuraId, Balance, BalancesConfig, BitacrossConfig, CouncilMembershipConfig, + GenesisConfig, ParachainInfoConfig, ParachainStakingConfig, PolkadotXcmConfig, SessionConfig, + SystemConfig, TechnicalCommitteeMembershipConfig, TeebagConfig, TeebagOperationalMode, UNIT, + WASM_BINARY, }; use sc_service::ChainType; use sc_telemetry::TelemetryEndpoints; @@ -230,5 +231,11 @@ fn generate_genesis( polkadot_xcm: PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION) }, transaction_payment: Default::default(), tokens: Default::default(), + teebag: TeebagConfig { + allow_sgx_debug_mode: true, + admin: None, + mode: TeebagOperationalMode::Development, + }, + bitacross: BitacrossConfig { admin: None }, } } diff --git a/node/src/chain_specs/rococo.rs b/node/src/chain_specs/rococo.rs index b6afd0d4b4..14a235e96c 100644 --- a/node/src/chain_specs/rococo.rs +++ b/node/src/chain_specs/rococo.rs @@ -256,5 +256,6 @@ fn generate_genesis( mode: TeebagOperationalMode::Development, }, bitacross: BitacrossConfig { admin: Some(root_key) }, + score_staking: Default::default(), } } diff --git a/pallets/bitacross/src/lib.rs b/pallets/bitacross/src/lib.rs index 5f5d6669a8..d19c6f8ca0 100644 --- a/pallets/bitacross/src/lib.rs +++ b/pallets/bitacross/src/lib.rs @@ -72,6 +72,7 @@ pub mod pallet { RelayerRemoved { who: Identity }, BtcWalletGenerated { pub_key: PubKey, account_id: T::AccountId }, EthWalletGenerated { pub_key: PubKey }, + VaultRemoved { who: T::AccountId }, } #[pallet::error] @@ -81,6 +82,7 @@ pub mod pallet { UnsupportedRelayerType, BtcWalletAlreadyExist, EthWalletAlreadyExist, + VaultNotExist, } #[pallet::genesis_config] @@ -123,23 +125,39 @@ pub mod pallet { #[pallet::call_index(1)] #[pallet::weight({195_000_000})] - pub fn add_relayer(origin: OriginFor, account: Identity) -> DispatchResult { + pub fn add_relayer(origin: OriginFor, account: Identity) -> DispatchResultWithPostInfo { Self::ensure_admin_or_root(origin)?; ensure!(account.is_substrate() || account.is_evm(), Error::::UnsupportedRelayerType); // we don't care if `account` already exists Relayer::::insert(account.clone(), ()); Self::deposit_event(Event::RelayerAdded { who: account }); - Ok(()) + Ok(Pays::No.into()) } #[pallet::call_index(2)] #[pallet::weight({195_000_000})] - pub fn remove_relayer(origin: OriginFor, account: Identity) -> DispatchResult { + pub fn remove_relayer( + origin: OriginFor, + account: Identity, + ) -> DispatchResultWithPostInfo { Self::ensure_admin_or_root(origin)?; ensure!(Relayer::::contains_key(&account), Error::::RelayerNotExist); Relayer::::remove(account.clone()); Self::deposit_event(Event::RelayerRemoved { who: account }); - Ok(()) + Ok(Pays::No.into()) + } + + #[pallet::call_index(3)] + #[pallet::weight({195_000_000})] + pub fn remove_vault( + origin: OriginFor, + account: T::AccountId, + ) -> DispatchResultWithPostInfo { + Self::ensure_admin_or_root(origin)?; + ensure!(Vault::::contains_key(&account), Error::::VaultNotExist); + Vault::::remove(account.clone()); + Self::deposit_event(Event::VaultRemoved { who: account }); + Ok(Pays::No.into()) } /// --------------------------------------------------- diff --git a/pallets/evm-assertions/src/lib.rs b/pallets/evm-assertions/src/lib.rs index c479bdae2b..f9b9bff531 100644 --- a/pallets/evm-assertions/src/lib.rs +++ b/pallets/evm-assertions/src/lib.rs @@ -39,8 +39,8 @@ pub mod pallet { #[derive(Encode, Decode, Clone, Default, Debug, PartialEq, Eq, TypeInfo)] pub struct Assertion { - byte_code: Vec, - secrets: Vec>, + pub byte_code: Vec, + pub secrets: Vec>, } #[pallet::config] @@ -58,6 +58,9 @@ pub mod pallet { /// Only a member of the Developers Collective can deploy the contract type ContractDevOrigin: EnsureOrigin; + + /// Only TEE-Workers can call some extrinsics + type TEECallOrigin: EnsureOrigin; } /// Map for storing assertion smart contract bytecode alongside with additional secrets @@ -71,6 +74,8 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { AssertionCreated { id: T::AssertionId, byte_code: Vec, secrets: Vec> }, + AssertionStored { id: T::AssertionId }, + AssertionVoided { id: T::AssertionId }, } #[pallet::error] @@ -97,5 +102,30 @@ pub mod pallet { Self::deposit_event(Event::AssertionCreated { id, byte_code, secrets }); Ok(Pays::No.into()) } + + /// Only called by the Identity-Worker + #[pallet::call_index(1)] + #[pallet::weight((T::DbWeight::get().read, DispatchClass::Normal, Pays::No))] + pub fn store_assertion( + origin: OriginFor, + id: T::AssertionId, + ) -> DispatchResultWithPostInfo { + let _ = T::TEECallOrigin::ensure_origin(origin)?; + Self::deposit_event(Event::AssertionStored { id }); + Ok(Pays::No.into()) + } + + /// Only called by the Identity-Worker + #[pallet::call_index(2)] + #[pallet::weight((T::DbWeight::get().write, DispatchClass::Normal, Pays::No))] + pub fn void_assertion( + origin: OriginFor, + id: T::AssertionId, + ) -> DispatchResultWithPostInfo { + let _ = T::TEECallOrigin::ensure_origin(origin)?; + Assertions::::remove(id); + Self::deposit_event(Event::AssertionVoided { id }); + Ok(Pays::No.into()) + } } } diff --git a/pallets/evm-assertions/src/mock.rs b/pallets/evm-assertions/src/mock.rs index 37df8644f2..8643f8a0cc 100644 --- a/pallets/evm-assertions/src/mock.rs +++ b/pallets/evm-assertions/src/mock.rs @@ -104,6 +104,7 @@ impl pallet_evm_assertions::Config for Test { type RuntimeEvent = RuntimeEvent; type AssertionId = H160; type ContractDevOrigin = frame_system::EnsureRoot; + type TEECallOrigin = frame_system::EnsureRoot; } parameter_types! { diff --git a/pallets/evm-assertions/src/tests.rs b/pallets/evm-assertions/src/tests.rs index b21861cf6a..bdad5ee0f5 100644 --- a/pallets/evm-assertions/src/tests.rs +++ b/pallets/evm-assertions/src/tests.rs @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU General Public License // along with Litentry. If not, see . -use crate::{mock::*, Error}; +use crate::{mock::*, Assertion, Error}; use frame_support::{assert_noop, assert_ok}; use sp_core::H160; @@ -63,3 +63,25 @@ fn should_not_create_new_assertion_if_exists() { ); }); } + +#[test] +fn should_remove_assertion_if_failed_to_store() { + new_test_ext().execute_with(|| { + let assertion_id: H160 = H160::from_slice(&[1u8; 20]); + let byte_code = [0u8; 256].to_vec(); + let secrets = vec![[2u8; 13].to_vec(), [3u8; 32].to_vec()]; + + assert_ok!(EvmAssertions::create_assertion( + RuntimeOrigin::root(), + assertion_id, + byte_code.clone(), + secrets.clone() + )); + + assert_eq!(EvmAssertions::assertions(assertion_id), Some(Assertion { byte_code, secrets })); + + assert_ok!(EvmAssertions::void_assertion(RuntimeOrigin::root(), assertion_id,)); + + assert_eq!(EvmAssertions::assertions(assertion_id), None); + }); +} diff --git a/pallets/identity-management/src/lib.rs b/pallets/identity-management/src/lib.rs index 8285fe0693..0510608bb4 100644 --- a/pallets/identity-management/src/lib.rs +++ b/pallets/identity-management/src/lib.rs @@ -141,7 +141,6 @@ pub mod pallet { detail: ErrorDetail, req_ext_hash: H256, }, - ImportScheduledEnclaveFailed, UnclassifiedError { prime_identity: Option, detail: ErrorDetail, @@ -361,8 +360,6 @@ pub mod pallet { detail, req_ext_hash, }), - IMPError::ImportScheduledEnclaveFailed => - Self::deposit_event(Event::ImportScheduledEnclaveFailed), IMPError::UnclassifiedError(detail) => Self::deposit_event(Event::UnclassifiedError { prime_identity, diff --git a/pallets/identity-management/src/mock.rs b/pallets/identity-management/src/mock.rs index 5b35890bbe..59e3ae392f 100644 --- a/pallets/identity-management/src/mock.rs +++ b/pallets/identity-management/src/mock.rs @@ -152,6 +152,7 @@ impl pallet_teebag::Config for Test { type MomentsPerDay = MomentsPerDay; type SetAdminOrigin = EnsureRoot; type MaxEnclaveIdentifier = ConstU32<3>; + type MaxAuthorizedEnclave = ConstU32<3>; } impl pallet_identity_management::Config for Test { diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index 3b65396adb..da6f558eb1 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -521,7 +521,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn delegator_state)] /// Get delegator state associated with an account if account is delegating else None - pub(crate) type DelegatorState = StorageMap< + pub type DelegatorState = StorageMap< _, Twox64Concat, T::AccountId, @@ -587,7 +587,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn total)] /// Total capital locked by this staking pallet - pub(crate) type Total = StorageValue<_, BalanceOf, ValueQuery>; + pub type Total = StorageValue<_, BalanceOf, ValueQuery>; #[pallet::storage] #[pallet::getter(fn candidate_pool)] diff --git a/pallets/score-staking/Cargo.toml b/pallets/score-staking/Cargo.toml new file mode 100644 index 0000000000..fb0497ccbb --- /dev/null +++ b/pallets/score-staking/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "pallet-score-staking" +description = 'pallet to stake based on the oracle score' +version = "0.1.0" +edition = "2021" + +[dependencies] +num-integer = { workspace = true } +parity-scale-codec = { workspace = true } +scale-info = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true, features = ["alloc"] } + +frame-benchmarking = { workspace = true, optional = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +core-primitives = { workspace = true } +pallet-parachain-staking = { workspace = true } + +[dev-dependencies] +sp-io = { workspace = true } +pallet-balances = { workspace = true } +sp-keyring = { workspace = true } + +[features] +default = ["std"] +std = [ + "parity-scale-codec/std", + "serde/std", + "serde_json/std", + "num-integer/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "pallet-balances/std", + "core-primitives/std", + "pallet-parachain-staking/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/pallets/score-staking/src/lib.rs b/pallets/score-staking/src/lib.rs new file mode 100644 index 0000000000..24d9238cc1 --- /dev/null +++ b/pallets/score-staking/src/lib.rs @@ -0,0 +1,471 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +//! A pallet served as a staking pool separated from `pallet-parachain-staking` +//! +//! Once started, the reward is calculated every `RoundInterval` blocks, the +//! snapshot of user state at that time will be used to calculate rewards. +//! +//! The yearly total issuance of this pool = YearlyIssuance * YearlyInflation, +//! based on it and `RoundInterval`, the reward per round can be calculated. +//! +//! The scores come from external origin (e.g. IDHub), upon updating the scores +//! the staked amount in pallet-parachain-staking is checked: users without any +//! staking will **NOT** be recorded. +//! +//! Then the round reward for a specific user is calculated by: +//! +//! total_round_rewards * (S(i) / S(a)) * ((T(i) / T(a)) ^ n/m) +//! +//! , where +//! S(i): the score of this user +//! T(i): the staked amount of this user +//! S(a): the total scores of all accounts in `Scores` storage +//! T(a): the total staked amount of all users, not only those in `Scores` storage + +#![cfg_attr(not(feature = "std"), no_std)] +#![allow(clippy::too_many_arguments)] + +use core_primitives::{DAYS, YEARS}; +use frame_support::{ + dispatch::DispatchResultWithPostInfo, + pallet_prelude::*, + traits::{Currency, Imbalance, LockableCurrency, ReservableCurrency, StorageVersion}, +}; +use pallet_parachain_staking as ParaStaking; +use sp_core::crypto::AccountId32; +use sp_runtime::{traits::CheckedSub, Perbill, SaturatedConversion}; + +pub use pallet::*; + +mod types; +pub use types::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +// Need this to convert hardcoded `AccountId32` to T::AccountId +pub trait AccountIdConvert { + fn convert(account: AccountId32) -> T::AccountId; +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + use core_primitives::Identity; + use frame_system::pallet_prelude::*; + use sp_runtime::traits::Zero; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + ParaStaking::Config { + type Currency: Currency + + ReservableCurrency + + LockableCurrency; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + #[pallet::constant] + type YearlyIssuance: Get>; + #[pallet::constant] + type YearlyInflation: Get; + #[pallet::constant] + /// Maximum number of entries (users) in the `Scores` storage, + /// this is to avoid iteration on an unbounded list in `on_initialize` + type MaxScoreUserCount: Get; + /// The origin who manages this pallet + type AdminOrigin: EnsureOrigin; + /// AccountId converter + type AccountIdConvert: AccountIdConvert; + } + + #[pallet::error] + pub enum Error { + // unthorized origin + UnauthorizedOrigin, + // the user account doesn't have an entry in parachain-staking + UserNotStaked, + // the user account has an entry but the total staked amount is (somehow) zero + UserStakedAmountZero, + // the user account doesn't exist in the registry + UserNotExist, + // convert `Identity` to substrate account failed + ConvertIdentityFailed, + // pool is not in running state + PoolNotRun, + // pool is already in running state + PoolAlreadyRunning, + // round index overflow + RoundIndexOverflow, + // the user claims more than what he has + InsufficientBalance, + // balance underflow + BalanceUnderflow, + // block number can't be converted to u32 + BlockNumberConvertError, + // total score overflow + TotalScoreOverflow, + // total score underflow + TotalScoreUnderflow, + // score user count overflow + ScoreUserCountOverflow, + // score user count underflow + ScoreUserCountUnderflow, + // when the score user count would exceed `MaxScoreUserCount` + MaxScoreUserCountReached, + } + + #[pallet::event] + #[pallet::generate_deposit(pub (crate) fn deposit_event)] + pub enum Event { + PoolStarted { start_block: BlockNumberFor }, + PoolStopped {}, + ScoreFeederSet { new_score_feeder: Option }, + RoundConfigSet { new_config: RoundSetting }, + ScoreUpdated { who: Identity, new_score: Score }, + ScoreRemoved { who: Identity }, + ScoreCleared {}, + RewardCalculated { total: BalanceOf, distributed: BalanceOf }, + RewardClaimed { who: T::AccountId, amount: BalanceOf }, + } + + #[pallet::storage] + #[pallet::getter(fn score_feeder)] + pub type ScoreFeeder = StorageValue<_, T::AccountId, OptionQuery>; + + #[pallet::storage] + #[pallet::getter(fn round)] + pub type Round = StorageValue<_, RoundInfo>, ValueQuery>; + + #[pallet::type_value] + pub fn DefaultRoundSetting() -> RoundSetting { + RoundSetting { interval: 7 * DAYS, stake_coef_n: 1, stake_coef_m: 2 } + } + + #[pallet::storage] + #[pallet::getter(fn round_config)] + pub type RoundConfig = + StorageValue<_, RoundSetting, ValueQuery, DefaultRoundSetting>; + + // use `Twox64Concat` and `T::AccountId` for faster and shorter storage + // we might have tens of thousands of entries + #[pallet::storage] + #[pallet::getter(fn scores)] + pub type Scores = + StorageMap<_, Twox64Concat, T::AccountId, ScorePayment>, OptionQuery>; + + /// keep track of how many entries in the `Scores` storage + #[pallet::storage] + #[pallet::getter(fn score_user_count)] + pub type ScoreUserCount = StorageValue<_, Score, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn total_score)] + pub type TotalScore = StorageValue<_, Score, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn state)] + pub type State = StorageValue<_, PoolState, ValueQuery>; + + #[pallet::genesis_config] + pub struct GenesisConfig { + pub state: PoolState, + pub marker: PhantomData, + } + + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + Self { state: PoolState::Stopped, marker: Default::default() } + } + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + State::::put(self.state); + } + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(now: BlockNumberFor) -> Weight { + let mut weight = T::DbWeight::get().reads_writes(1, 0); // Self::state() + + if Self::state() == PoolState::Stopped { + return weight + } + + let mut r = Round::::get(); + weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 0)); + + if !is_modulo(now - r.start_block, Self::round_config().interval.into()) { + // nothing to do there + return weight + } + + // We are about to start a new round + // 1. update round info + r.index = r.index.saturating_add(1); + r.start_block = now; + Round::::put(r); + weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + + // 2. calculate payout + let round_reward: BalanceOf = (T::YearlyInflation::get() * T::YearlyIssuance::get() / + YEARS.into()) * Self::round_config().interval.into(); + let round_reward_u128 = round_reward.saturated_into::(); + + let total_stake_u128 = ParaStaking::Pallet::::total().saturated_into::(); + let total_score = Self::total_score(); + let n = Self::round_config().stake_coef_n; + let m = Self::round_config().stake_coef_m; + + let mut all_user_reward = BalanceOf::::zero(); + + for (a, mut p) in Scores::::iter() { + let user_stake_u128 = ParaStaking::Pallet::::delegator_state(&a) + .map(|s| s.total) + .unwrap_or_default() + .saturated_into::(); + let user_reward_u128 = round_reward_u128 + .saturating_mul(p.score.into()) + .saturating_div(total_score.into()) + .saturating_mul(num_integer::Roots::nth_root(&user_stake_u128.pow(n), m)) + .saturating_div(num_integer::Roots::nth_root(&total_stake_u128.pow(n), m)); + let user_reward = user_reward_u128.saturated_into::>(); + + p.last_round_reward = user_reward; + p.total_reward += user_reward; + p.unpaid_reward += user_reward; + all_user_reward += user_reward; + Scores::::insert(&a, p); + weight = weight.saturating_add(T::DbWeight::get().reads_writes(2, 1)); + } + + Self::deposit_event(Event::::RewardCalculated { + total: round_reward, + distributed: all_user_reward, + }); + + weight + } + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight((2 * T::DbWeight::get().write, DispatchClass::Normal))] + pub fn set_score_feeder( + origin: OriginFor, + new_score_feeder: T::AccountId, + ) -> DispatchResultWithPostInfo { + T::AdminOrigin::ensure_origin(origin)?; + ScoreFeeder::::put(new_score_feeder.clone()); + Self::deposit_event(Event::ScoreFeederSet { new_score_feeder: Some(new_score_feeder) }); + Ok(Pays::No.into()) + } + + /// Start (or restart) a currently stopped pool + /// + /// It: + /// - sets the RoundInfo.start_block to the current block number + /// - advances the round index + #[pallet::call_index(1)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn start_pool(origin: OriginFor) -> DispatchResultWithPostInfo { + T::AdminOrigin::ensure_origin(origin)?; + ensure!(Self::state() == PoolState::Stopped, Error::::PoolAlreadyRunning); + State::::put(PoolState::Running); + let start_block = frame_system::Pallet::::block_number(); + let mut r = Round::::take(); + r.index = r.index.checked_add(1).ok_or(Error::::RoundIndexOverflow)?; + r.start_block = start_block; + Round::::put(r); + Self::deposit_event(Event::PoolStarted { start_block }); + Ok(Pays::No.into()) + } + + /// Stop a currently running pool, should be called as caution + #[pallet::call_index(2)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn stop_pool(origin: OriginFor) -> DispatchResultWithPostInfo { + T::AdminOrigin::ensure_origin(origin)?; + ensure!(Self::state() == PoolState::Running, Error::::PoolNotRun); + State::::put(PoolState::Stopped); + Self::deposit_event(Event::PoolStopped {}); + Ok(Pays::No.into()) + } + + #[pallet::call_index(3)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn set_round_config( + origin: OriginFor, + config: RoundSetting, + ) -> DispatchResultWithPostInfo { + T::AdminOrigin::ensure_origin(origin)?; + RoundConfig::::put(config); + Self::deposit_event(Event::RoundConfigSet { new_config: config }); + Ok(Pays::No.into()) + } + + // Intentionally use `Identity` type to lower the hurdle of mapping to the + // desired substrate account as it's handled on-chain instead of by client. + // + // Subject to requirement change though + #[pallet::call_index(4)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn update_score( + origin: OriginFor, + user: Identity, + score: Score, + ) -> DispatchResultWithPostInfo { + ensure!( + Some(ensure_signed(origin)?) == Self::score_feeder(), + Error::::UnauthorizedOrigin + ); + let account = T::AccountIdConvert::convert( + user.to_account_id().ok_or(Error::::ConvertIdentityFailed)?, + ); + Scores::::try_mutate(&account, |payment| { + let state = ParaStaking::Pallet::::delegator_state(&account) + .ok_or(Error::::UserNotStaked)?; + ensure!(state.total > 0u32.into(), Error::::UserStakedAmountZero); + + match payment { + Some(s) => { + Self::update_total_score(s.score, score)?; + s.score = score; + *payment = Some(*s); + }, + None => { + Self::update_total_score(0, score)?; + Self::inc_score_user_count()?; + *payment = Some(ScorePayment { score, ..Default::default() }); + }, + } + Ok::<(), Error>(()) + })?; + Self::deposit_event(Event::ScoreUpdated { who: user, new_score: score }); + Ok(Pays::No.into()) + } + + #[pallet::call_index(5)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn remove_score(origin: OriginFor, user: Identity) -> DispatchResultWithPostInfo { + // only admin can remove entries in `Scores` + T::AdminOrigin::ensure_origin(origin)?; + let account = T::AccountIdConvert::convert( + user.to_account_id().ok_or(Error::::ConvertIdentityFailed)?, + ); + let user_score = Scores::::get(&account).ok_or(Error::::UserNotExist)?.score; + Self::update_total_score(user_score, 0)?; + Self::dec_score_user_count()?; + Scores::::remove(&account); + Self::deposit_event(Event::ScoreRemoved { who: user }); + Ok(Pays::No.into()) + } + + #[pallet::call_index(6)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn clear_score(origin: OriginFor) -> DispatchResultWithPostInfo { + // only admin can clear all entries in `Scores` + T::AdminOrigin::ensure_origin(origin)?; + let _ = Scores::::clear(u32::MAX, None); + TotalScore::::put(0u32); + ScoreUserCount::::put(0u32); + Self::deposit_event(Event::ScoreCleared {}); + Ok(Pays::No.into()) + } + + #[pallet::call_index(7)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn claim(origin: OriginFor, amount: BalanceOf) -> DispatchResultWithPostInfo { + let account = ensure_signed(origin)?; + Scores::::try_mutate(&account, |payment| { + let mut p = payment.take().ok_or(Error::::UserNotExist)?; + ensure!(amount <= p.unpaid_reward, Error::::InsufficientBalance); + let rewarded = + ::Currency::deposit_into_existing(&account, amount)? + .peek(); + p.unpaid_reward = + p.unpaid_reward.checked_sub(&rewarded).ok_or(Error::::BalanceUnderflow)?; + *payment = Some(p); + Self::deposit_event(Event::RewardClaimed { + who: account.clone(), + amount: rewarded, + }); + Ok(().into()) + }) + } + + #[pallet::call_index(8)] + #[pallet::weight((195_000_000, DispatchClass::Normal))] + pub fn claim_all(origin: OriginFor) -> DispatchResultWithPostInfo { + let account = ensure_signed(origin.clone())?; + let payment = Scores::::get(&account).ok_or(Error::::UserNotExist)?; + Self::claim(origin, payment.unpaid_reward) + } + } +} + +impl Pallet { + fn update_total_score(due_sub: Score, due_add: Score) -> Result<(), Error> { + let mut s = Self::total_score(); + if due_sub > 0 { + s = s.checked_sub(due_sub).ok_or(Error::::TotalScoreUnderflow)?; + } + if due_add > 0 { + s = s.checked_add(due_add).ok_or(Error::::TotalScoreOverflow)?; + } + TotalScore::::put(s); + Ok(()) + } + + fn inc_score_user_count() -> Result<(), Error> { + let mut c = Self::score_user_count(); + ensure!(c < T::MaxScoreUserCount::get(), Error::::MaxScoreUserCountReached); + c = c.checked_add(1).ok_or(Error::::ScoreUserCountOverflow)?; + ScoreUserCount::::put(c); + Ok(()) + } + + fn dec_score_user_count() -> Result<(), Error> { + let mut c = Self::score_user_count(); + c = c.checked_sub(1).ok_or(Error::::ScoreUserCountUnderflow)?; + ScoreUserCount::::put(c); + Ok(()) + } +} + +fn is_modulo + sp_std::ops::Rem>( + dividend: BlockNumber, + divisor: BlockNumber, +) -> bool { + dividend % divisor == BlockNumber::from(0u32) +} diff --git a/pallets/score-staking/src/mock.rs b/pallets/score-staking/src/mock.rs new file mode 100644 index 0000000000..b005c1121c --- /dev/null +++ b/pallets/score-staking/src/mock.rs @@ -0,0 +1,241 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +#![allow(dead_code, unused_imports, const_item_mutation)] +use crate::{ + self as pallet_score_staking, AccountIdConvert, Config, Perbill, PoolState, RoundSetting, +}; +use frame_support::{ + assert_ok, construct_runtime, ord_parameter_types, + pallet_prelude::GenesisBuild, + parameter_types, + traits::{OnFinalize, OnInitialize}, +}; +use frame_system as system; +use frame_system::{EnsureRoot, EnsureSignedBy}; +use sp_core::{ConstU128, ConstU32, H256}; +use sp_keyring::AccountKeyring; +use sp_runtime::{ + generic, + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + Percent, +}; + +pub type Signature = sp_runtime::MultiSignature; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; +pub type Address = sp_runtime::MultiAddress; + +pub type BlockNumber = u32; +pub type Header = generic::Header; +pub type Block = generic::Block; +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; + +pub type SignedExtra = ( + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, +); + +construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system, + Balances: pallet_balances, + ParachainStaking: pallet_parachain_staking, + ScoreStaking: pallet_score_staking, + } +); + +parameter_types! { + pub const BlockHashCount: u32 = 250; +} +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type RuntimeCall = RuntimeCall; + type BlockNumber = BlockNumber; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +pub type Balance = u128; +pub const UNIT: Balance = 1_000_000_000_000; + +parameter_types! { + pub const ExistentialDeposit: u128 = 1; +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = (); + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = (); + type MaxFreezes = (); +} + +parameter_types! { + pub const MinBlocksPerRound: u32 = 3; + pub const DefaultBlocksPerRound: u32 = 5; + pub const LeaveCandidatesDelay: u32 = 2; + pub const CandidateBondLessDelay: u32 = 2; + pub const LeaveDelegatorsDelay: u32 = 2; + pub const RevokeDelegationDelay: u32 = 2; + pub const DelegationBondLessDelay: u32 = 2; + pub const RewardPaymentDelay: u32 = 2; + pub const MinSelectedCandidates: u32 = 5; + pub const MaxTopDelegationsPerCandidate: u32 = 4; + pub const MaxBottomDelegationsPerCandidate: u32 = 4; + pub const MaxDelegationsPerDelegator: u32 = 4; + pub const DefaultCollatorCommission: Perbill = Perbill::from_percent(20); + pub const DefaultParachainBondReservePercent: Percent = Percent::from_percent(30); + pub const MinCollatorStk: u128 = 10; + pub const MinDelegatorStk: u128 = 5; + pub const MinDelegation: u128 = 3; +} +impl pallet_parachain_staking::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type MonetaryGovernanceOrigin = EnsureRoot; + type MinBlocksPerRound = MinBlocksPerRound; + type DefaultBlocksPerRound = DefaultBlocksPerRound; + type LeaveCandidatesDelay = LeaveCandidatesDelay; + type CandidateBondLessDelay = CandidateBondLessDelay; + type LeaveDelegatorsDelay = LeaveDelegatorsDelay; + type RevokeDelegationDelay = RevokeDelegationDelay; + type DelegationBondLessDelay = DelegationBondLessDelay; + type RewardPaymentDelay = RewardPaymentDelay; + type MinSelectedCandidates = MinSelectedCandidates; + type MaxTopDelegationsPerCandidate = MaxTopDelegationsPerCandidate; + type MaxBottomDelegationsPerCandidate = MaxBottomDelegationsPerCandidate; + type MaxDelegationsPerDelegator = MaxDelegationsPerDelegator; + type DefaultCollatorCommission = DefaultCollatorCommission; + type DefaultParachainBondReservePercent = DefaultParachainBondReservePercent; + type MinCollatorStk = MinCollatorStk; + type MinCandidateStk = MinCollatorStk; + type MinDelegatorStk = MinDelegatorStk; + type MinDelegation = MinDelegation; + type OnCollatorPayout = (); + type OnNewRound = (); + type WeightInfo = (); + type IssuanceAdapter = (); +} + +parameter_types! { + pub const DefaultYearlyInflation: Perbill = Perbill::from_perthousand(5); +} + +impl pallet_score_staking::Config for Test { + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type AccountIdConvert = IdentityAccountIdConvert; + type AdminOrigin = EnsureRoot; + type YearlyIssuance = ConstU128<{ 100_000_000 * UNIT }>; + type YearlyInflation = DefaultYearlyInflation; + type MaxScoreUserCount = ConstU32<2>; +} + +pub fn alice() -> AccountId { + AccountKeyring::Alice.to_account_id() +} + +pub fn bob() -> AccountId { + AccountKeyring::Bob.to_account_id() +} + +pub fn charlie() -> AccountId { + AccountKeyring::Charlie.to_account_id() +} + +pub fn new_test_ext(fast_round: bool) -> sp_io::TestExternalities { + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { balances: vec![(alice(), 2 * UNIT)] } + .assimilate_storage(&mut t) + .unwrap(); + + let genesis_config: pallet_score_staking::GenesisConfig = + crate::GenesisConfig { state: PoolState::Stopped, marker: Default::default() }; + + GenesisBuild::::assimilate_storage(&genesis_config, &mut t).unwrap(); + + let mut ext: sp_io::TestExternalities = t.into(); + ext.execute_with(|| { + System::set_block_number(1); + assert_ok!(ScoreStaking::set_score_feeder(RuntimeOrigin::root(), alice())); + if fast_round { + assert_ok!(ScoreStaking::set_round_config( + RuntimeOrigin::root(), + RoundSetting { interval: 5, stake_coef_n: 1, stake_coef_m: 2 } + )); + } + }); + ext +} + +/// Run until a particular block. +pub fn run_to_block(n: u32) { + while System::block_number() < n { + ScoreStaking::on_finalize(System::block_number()); + ParachainStaking::on_finalize(System::block_number()); + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + ParachainStaking::on_initialize(System::block_number()); + ScoreStaking::on_initialize(System::block_number()); + } +} + +pub struct IdentityAccountIdConvert; + +impl AccountIdConvert for IdentityAccountIdConvert { + fn convert(account: AccountId) -> ::AccountId { + account + } +} diff --git a/pallets/score-staking/src/tests.rs b/pallets/score-staking/src/tests.rs new file mode 100644 index 0000000000..32bebe1e7c --- /dev/null +++ b/pallets/score-staking/src/tests.rs @@ -0,0 +1,344 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +#![allow(dead_code, unused_imports)] + +use crate::{mock::*, Error, Event, PoolState, RoundInfo, RoundSetting, ScorePayment}; +use core_primitives::{DAYS, YEARS}; +use frame_support::{assert_err, assert_ok}; +use pallet_parachain_staking::Delegator; +use sp_runtime::Perbill; + +fn round_reward() -> Balance { + (Perbill::from_perthousand(5) * 100_000_000 * UNIT / (YEARS as u128)) * 5 +} + +#[test] +fn default_state_works() { + new_test_ext(false).execute_with(|| { + assert_eq!(ScoreStaking::state(), PoolState::Stopped); + assert_eq!( + ScoreStaking::round_config(), + RoundSetting { interval: 7 * DAYS, stake_coef_n: 1, stake_coef_m: 2 } + ); + assert_eq!(ScoreStaking::score_feeder().unwrap(), alice()); + assert_eq!(ScoreStaking::round(), RoundInfo { index: 0, start_block: 0 }); + }) +} + +#[test] +fn start_stop_pool_works() { + new_test_ext(true).execute_with(|| { + run_to_block(2); + assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); + assert_eq!(ScoreStaking::state(), PoolState::Running); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::PoolStarted { + start_block: 2, + })); + assert_eq!(ScoreStaking::round(), RoundInfo { index: 1, start_block: 2 }); + + run_to_block(6); + assert_eq!(ScoreStaking::round(), RoundInfo { index: 1, start_block: 2 }); + + run_to_block(7); + assert_eq!(ScoreStaking::round(), RoundInfo { index: 2, start_block: 7 }); + + run_to_block(8); + assert_ok!(ScoreStaking::stop_pool(RuntimeOrigin::root())); + assert_eq!(ScoreStaking::state(), PoolState::Stopped); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::PoolStopped {})); + assert_eq!(ScoreStaking::round(), RoundInfo { index: 2, start_block: 7 }); + + run_to_block(20); + assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); + assert_eq!(ScoreStaking::state(), PoolState::Running); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::PoolStarted { + start_block: 20, + })); + assert_eq!(ScoreStaking::round(), RoundInfo { index: 3, start_block: 20 }); + }) +} + +#[test] +fn set_round_config_works() { + new_test_ext(true).execute_with(|| { + run_to_block(2); + assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); + assert_eq!(ScoreStaking::round(), RoundInfo { index: 1, start_block: 2 }); + + run_to_block(3); + assert_ok!(ScoreStaking::set_round_config( + RuntimeOrigin::root(), + RoundSetting { interval: 3, stake_coef_n: 1, stake_coef_m: 2 } + )); + + assert_eq!(ScoreStaking::round(), RoundInfo { index: 1, start_block: 2 }); + assert_eq!(ScoreStaking::round_config().interval, 3); + + run_to_block(5); + assert_eq!(ScoreStaking::round(), RoundInfo { index: 2, start_block: 5 }); + + run_to_block(6); + assert_ok!(ScoreStaking::set_round_config( + RuntimeOrigin::root(), + RoundSetting { interval: 5, stake_coef_n: 1, stake_coef_m: 2 } + )); + assert_eq!(ScoreStaking::round(), RoundInfo { index: 2, start_block: 5 }); + + run_to_block(9); + assert_eq!(ScoreStaking::round(), RoundInfo { index: 2, start_block: 5 }); + + run_to_block(10); + assert_eq!(ScoreStaking::round(), RoundInfo { index: 3, start_block: 10 }); + }); +} + +#[test] +fn default_mint_works() { + new_test_ext(true).execute_with(|| { + run_to_block(2); + assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); + + // run to next reward distribution round + run_to_block(7); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { + total: round_reward(), + distributed: 0, + })); + }); +} + +#[test] +fn score_update_checks_staking() { + new_test_ext(true).execute_with(|| { + run_to_block(2); + assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); + + run_to_block(3); + assert_err!( + ScoreStaking::update_score(RuntimeOrigin::signed(alice()), alice().into(), 2000), + Error::::UserNotStaked + ); + }); +} + +#[test] +#[allow(clippy::identity_op)] +fn score_staking_works() { + new_test_ext(true).execute_with(|| { + run_to_block(2); + assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); + + run_to_block(3); + pallet_parachain_staking::DelegatorState::::insert( + alice(), + Delegator::new(bob(), bob(), 900), + ); + pallet_parachain_staking::Total::::put(900); + + assert_ok!(ScoreStaking::update_score(RuntimeOrigin::signed(alice()), alice().into(), 500)); + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { score: 500, total_reward: 0, last_round_reward: 0, unpaid_reward: 0 } + ); + assert_eq!(ScoreStaking::total_score(), 500); + assert_eq!(ScoreStaking::score_user_count(), 1); + + assert_ok!(ScoreStaking::update_score( + RuntimeOrigin::signed(alice()), + alice().into(), + 2000 + )); + assert_eq!(ScoreStaking::scores(alice()).unwrap().score, 2000); + assert_eq!(ScoreStaking::total_score(), 2000); + assert_eq!(ScoreStaking::score_user_count(), 1); + + // run to next reward distribution round, alice should win all rewards + run_to_block(7); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { + total: round_reward(), + distributed: round_reward(), + })); + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: 2000, + total_reward: round_reward(), + last_round_reward: round_reward(), + unpaid_reward: round_reward(), + } + ); + + // alice's winning should accumulate + run_to_block(12); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { + total: round_reward(), + distributed: round_reward(), + })); + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: 2000, + total_reward: 2 * round_reward(), + last_round_reward: round_reward(), + unpaid_reward: 2 * round_reward(), + } + ); + + // increase the total staked amount, alice should win less + run_to_block(13); + pallet_parachain_staking::Total::::put(1600); + + run_to_block(17); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { + total: round_reward(), + distributed: round_reward() * 3 / 4, + })); + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: 2000, + total_reward: 2 * round_reward() + round_reward() * 3 / 4, + last_round_reward: round_reward() * 3 / 4, + unpaid_reward: 2 * round_reward() + round_reward() * 3 / 4, + } + ); + + // add bob's score + run_to_block(18); + pallet_parachain_staking::DelegatorState::::insert( + bob(), + Delegator::new(alice(), alice(), 1600), + ); + assert_ok!(ScoreStaking::update_score(RuntimeOrigin::signed(alice()), bob().into(), 1000)); + pallet_parachain_staking::Total::::put(2500); + assert_eq!(ScoreStaking::total_score(), 3000); + assert_eq!(ScoreStaking::score_user_count(), 2); + + run_to_block(22); + // System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { + // total: round_reward(), + // distributed: round_reward() * 2 * 3 / (3 * 5) + round_reward() * 1 * 4 / (3 * 5), + // })); + + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: 2000, + total_reward: 2 * round_reward() + + round_reward() * 3 / 4 + + round_reward() * 2 * 3 / (3 * 5), + last_round_reward: round_reward() * 2 * 3 / (3 * 5), + unpaid_reward: 2 * round_reward() + + round_reward() * 3 / 4 + + round_reward() * 2 * 3 / (3 * 5), + } + ); + + assert_eq!( + ScoreStaking::scores(bob()).unwrap(), + ScorePayment { + score: 1000, + total_reward: round_reward() * 1 * 4 / (3 * 5), + last_round_reward: round_reward() * 1 * 4 / (3 * 5), + unpaid_reward: round_reward() * 1 * 4 / (3 * 5), + } + ); + + // update more scores will error out + pallet_parachain_staking::DelegatorState::::insert( + charlie(), + Delegator::new(alice(), alice(), 7000), + ); + assert_err!( + ScoreStaking::update_score(RuntimeOrigin::signed(alice()), charlie().into(), 1000), + Error::::MaxScoreUserCountReached + ); + }); +} + +#[test] +fn claim_works() { + new_test_ext(true).execute_with(|| { + run_to_block(2); + assert_ok!(ScoreStaking::start_pool(RuntimeOrigin::root())); + + run_to_block(3); + pallet_parachain_staking::DelegatorState::::insert( + alice(), + Delegator::new(bob(), bob(), 1000), + ); + pallet_parachain_staking::Total::::put(1000); + + assert_ok!(ScoreStaking::update_score( + RuntimeOrigin::signed(alice()), + alice().into(), + 2000 + )); + + // run to next reward distribution round, alice should win all rewards + run_to_block(7); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardCalculated { + total: round_reward(), + distributed: round_reward(), + })); + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: 2000, + total_reward: round_reward(), + last_round_reward: round_reward(), + unpaid_reward: round_reward(), + } + ); + + assert_ok!(ScoreStaking::claim(RuntimeOrigin::signed(alice()), 200)); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardClaimed { + who: alice(), + amount: 200, + })); + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: 2000, + total_reward: round_reward(), + last_round_reward: round_reward(), + unpaid_reward: round_reward() - 200, + } + ); + + assert_ok!(ScoreStaking::claim_all(RuntimeOrigin::signed(alice()))); + System::assert_last_event(RuntimeEvent::ScoreStaking(Event::::RewardClaimed { + who: alice(), + amount: round_reward() - 200, + })); + assert_eq!( + ScoreStaking::scores(alice()).unwrap(), + ScorePayment { + score: 2000, + total_reward: round_reward(), + last_round_reward: round_reward(), + unpaid_reward: 0, + } + ); + + // continue to claim will error out + assert_err!( + ScoreStaking::claim(RuntimeOrigin::signed(alice()), 100), + Error::::InsufficientBalance + ); + }); +} diff --git a/pallets/score-staking/src/types.rs b/pallets/score-staking/src/types.rs new file mode 100644 index 0000000000..1456f4e67d --- /dev/null +++ b/pallets/score-staking/src/types.rs @@ -0,0 +1,86 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use frame_support::pallet_prelude::*; +use parity_scale_codec::{Decode, Encode}; +use serde::{Deserialize, Serialize}; + +pub type RoundIndex = u32; +/// we force u32 type, BlockNumberFor implements `AtLeast32BitUnsigned` so it's safe +pub type RoundDuration = u32; +pub type Score = u32; + +/// an on/off flag +#[derive( + Clone, Copy, Default, PartialEq, Eq, Encode, Decode, Debug, TypeInfo, Deserialize, Serialize, +)] +pub enum PoolState { + #[default] + #[codec(index = 0)] + Stopped, + #[codec(index = 1)] + Running, +} + +#[derive( + Copy, + Clone, + Default, + PartialEq, + Eq, + Encode, + Decode, + RuntimeDebug, + TypeInfo, + Deserialize, + Serialize, +)] +pub struct RoundInfo { + /// Current round index + pub index: RoundIndex, + /// The start block of the current round + pub start_block: BlockNumber, +} + +#[derive(Copy, Clone, Default, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct RoundSetting { + /// Interval of rounds in block number + pub interval: RoundDuration, + /// the `n` of stake coefficient that is applied to stake calculation + pub stake_coef_n: u32, + /// the `m` of stake coefficient that is applied to stake calculation + pub stake_coef_m: u32, +} + +#[derive( + Copy, + Clone, + Default, + PartialEq, + Eq, + Encode, + Decode, + RuntimeDebug, + TypeInfo, + Deserialize, + Serialize, +)] +pub struct ScorePayment { + pub score: Score, + pub total_reward: Balance, + pub last_round_reward: Balance, + pub unpaid_reward: Balance, +} diff --git a/pallets/teebag/src/lib.rs b/pallets/teebag/src/lib.rs index 6069af269c..1b9ce40fc3 100644 --- a/pallets/teebag/src/lib.rs +++ b/pallets/teebag/src/lib.rs @@ -18,7 +18,7 @@ #![allow(clippy::too_many_arguments)] use frame_support::{ - dispatch::{DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo}, + dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo}, ensure, pallet_prelude::*, traits::Get, @@ -65,10 +65,12 @@ pub mod pallet { type MomentsPerDay: Get; /// The origin who can set the admin account type SetAdminOrigin: EnsureOrigin; - /// Maximum number of enclave identifiers allowed to be registered for a specific - /// `worker_type` + /// Maximum number of enclave identifiers allowed to be registered for a given `worker_type` #[pallet::constant] type MaxEnclaveIdentifier: Get; + /// Maximum number of authorized enclave for a given `worker_type` + #[pallet::constant] + type MaxAuthorizedEnclave: Get; } // TODO: maybe add more sidechain lifecycle events @@ -89,6 +91,14 @@ pub mod pallet { EnclaveRemoved { who: T::AccountId, }, + EnclaveAuthorized { + worker_type: WorkerType, + mrenclave: MrEnclave, + }, + EnclaveUnauthorized { + worker_type: WorkerType, + mrenclave: MrEnclave, + }, OpaqueTaskPosted { request: RsaRequest, }, @@ -102,15 +112,6 @@ pub mod pallet { who: T::AccountId, sidechain_block_number: SidechainBlockNumber, }, - ScheduledEnclaveSet { - worker_type: WorkerType, - sidechain_block_number: SidechainBlockNumber, - mrenclave: MrEnclave, - }, - ScheduledEnclaveRemoved { - worker_type: WorkerType, - sidechain_block_number: SidechainBlockNumber, - }, } #[pallet::error] @@ -129,6 +130,8 @@ pub mod pallet { InvalidAttestationType, /// The enclave cannot attest, because its building mode is not allowed. InvalidSgxMode, + /// The specified dcap provider is not yet supported + DcapProviderNotSupported, /// The enclave doesn't exist. EnclaveNotExist, /// The enclave identifier doesn't exist. @@ -147,14 +150,18 @@ pub mod pallet { /// The worker mode is unexpected, because e.g. a non-sidechain worker calls /// sidechain specific extrinsic UnexpectedWorkerMode, - /// Can not found the desired scheduled enclave. - ScheduledEnclaveNotExist, - /// Enclave not in the scheduled list, therefore unexpected. - EnclaveNotInSchedule, + /// The authorized enclave doesn't exist. + AuthorizedEnclaveNotExist, + /// The authorized enclave already exists. + AuthorizedEnclaveAlreadyExist, + /// Enclave not authorized upon registration. + EnclaveNotAuthorized, /// The provided collateral data is invalid. CollateralInvalid, /// MaxEnclaveIdentifier overflow. MaxEnclaveIdentifierOverflow, + /// MaxAuthorizedEnclave overflow. + MaxAuthorizedEnclaveOverflow, /// A proposed block is unexpected. ReceivedUnexpectedSidechainBlock, /// The value for the next finalization candidate is invalid. @@ -219,11 +226,36 @@ pub mod pallet { // Theorectically we could always push the enclave in `register_enclave`, but we want to // limit the mrenclave that can be registered, as the parachain is supposed to process enclaves // with specific mrenclaves. + // + // Update: + // this storage is deprecated and will be removed (discarded) once we move to litentry-parachain + // see https://linear.app/litentry/issue/P-882/simplify-scheduledenclave-usage + // + // use `AuthorizedEnclave` instead #[pallet::storage] #[pallet::getter(fn scheduled_enclave)] pub type ScheduledEnclave = StorageMap<_, Blake2_128Concat, (WorkerType, SidechainBlockNumber), MrEnclave, OptionQuery>; + // Keep trace of a list of authorized (mr-)enclaves, enclave registration with non-authorized + // mrenclave will be rejected + // + // Removing an mrenclave within `AuthorizedEnclave`` will cause the enclave to be removed from + // the EnclaveRegistry too, which stops the sidechain from producing blocks as it will never be + // able to claim the slot. Additionally, the vc-task-runner is informed to stop operating too. + // + // In this case, restarting the worker won't help, as the mrenclave is not authorized anymore, + // so the registration will fail in the first place. + #[pallet::storage] + #[pallet::getter(fn authorized_enclave)] + pub type AuthorizedEnclave = StorageMap< + _, + Blake2_128Concat, + WorkerType, + BoundedVec, + ValueQuery, + >; + #[pallet::storage] #[pallet::getter(fn latest_sidechain_block_confirmation)] pub type LatestSidechainBlockConfirmation = @@ -372,39 +404,40 @@ pub mod pallet { #[pallet::call_index(6)] #[pallet::weight((195_000_000, DispatchClass::Normal))] - pub fn set_scheduled_enclave( + pub fn force_add_authorized_enclave( origin: OriginFor, worker_type: WorkerType, - sidechain_block_number: SidechainBlockNumber, mrenclave: MrEnclave, ) -> DispatchResultWithPostInfo { Self::ensure_admin_or_root(origin)?; - ScheduledEnclave::::insert((worker_type, sidechain_block_number), mrenclave); - Self::deposit_event(Event::ScheduledEnclaveSet { - worker_type, - sidechain_block_number, - mrenclave, - }); + + AuthorizedEnclave::::try_mutate(worker_type, |v| { + ensure!(!v.contains(&mrenclave), Error::::AuthorizedEnclaveAlreadyExist); + v.try_push(mrenclave).map_err(|_| Error::::MaxAuthorizedEnclaveOverflow) + })?; + + Self::deposit_event(Event::EnclaveAuthorized { worker_type, mrenclave }); Ok(Pays::No.into()) } #[pallet::call_index(7)] #[pallet::weight((195_000_000, DispatchClass::Normal))] - pub fn remove_scheduled_enclave( + pub fn force_remove_authorized_enclave( origin: OriginFor, worker_type: WorkerType, - sidechain_block_number: SidechainBlockNumber, + mrenclave: MrEnclave, ) -> DispatchResultWithPostInfo { - Self::ensure_admin_or_root(origin)?; - ensure!( - ScheduledEnclave::::contains_key((worker_type, sidechain_block_number)), - Error::::ScheduledEnclaveNotExist - ); - ScheduledEnclave::::remove((worker_type, sidechain_block_number)); - Self::deposit_event(Event::ScheduledEnclaveRemoved { - worker_type, - sidechain_block_number, - }); + Self::ensure_admin_or_root(origin.clone())?; + + AuthorizedEnclave::::try_mutate(worker_type, |v| { + ensure!(v.contains(&mrenclave), Error::::AuthorizedEnclaveNotExist); + v.retain(|e| e != &mrenclave); + Ok::<(), DispatchErrorWithPostInfo>(()) + })?; + + Self::force_remove_enclave_by_mrenclave(origin, mrenclave)?; + + Self::deposit_event(Event::EnclaveUnauthorized { worker_type, mrenclave }); Ok(Pays::No.into()) } @@ -448,7 +481,8 @@ pub mod pallet { enclave.last_seen_timestamp = report.timestamp; enclave.sgx_build_mode = report.build_mode; }, - AttestationType::Dcap(_) => { + AttestationType::Dcap(provider) => { + ensure!(provider == DcapProvider::Intel, Error::::DcapProviderNotSupported); let report = Self::verify_dcap(&sender, attestation)?; enclave.mrenclave = report.mr_enclave; enclave.last_seen_timestamp = report.timestamp; @@ -464,19 +498,23 @@ pub mod pallet { return Err(Error::::InvalidSgxMode.into()) } ensure!( - ScheduledEnclave::::iter_values().any(|m| m == enclave.mrenclave), - Error::::EnclaveNotInSchedule + AuthorizedEnclave::::get(worker_type).contains(&enclave.mrenclave), + Error::::EnclaveNotAuthorized ); }, OperationalMode::Development => { - // populate the registry if the entry doesn't exist - if !ScheduledEnclave::::contains_key((worker_type, 0)) { - ScheduledEnclave::::insert((worker_type, 0), enclave.mrenclave); - } + AuthorizedEnclave::::try_mutate(worker_type, |v| { + if !v.contains(&enclave.mrenclave) { + v.try_push(enclave.mrenclave) + .map_err(|_| Error::::MaxAuthorizedEnclaveOverflow) + } else { + Ok(()) + } + })?; }, }; Self::add_enclave(&sender, &enclave)?; - Ok(().into()) + Ok(Pays::No.into()) } #[pallet::call_index(9)] @@ -484,7 +522,7 @@ pub mod pallet { pub fn unregister_enclave(origin: OriginFor) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; Self::remove_enclave(&sender)?; - Ok(().into()) + Ok(Pays::No.into()) } #[pallet::call_index(10)] @@ -525,10 +563,13 @@ pub mod pallet { #[pallet::call_index(20)] #[pallet::weight((195_000_000, DispatchClass::Normal))] - pub fn post_opaque_task(origin: OriginFor, request: RsaRequest) -> DispatchResult { + pub fn post_opaque_task( + origin: OriginFor, + request: RsaRequest, + ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; Self::deposit_event(Event::OpaqueTaskPosted { request }); - Ok(()) + Ok(Pays::No.into()) } #[pallet::call_index(21)] diff --git a/pallets/teebag/src/mock.rs b/pallets/teebag/src/mock.rs index 945948cdda..3577fd503c 100644 --- a/pallets/teebag/src/mock.rs +++ b/pallets/teebag/src/mock.rs @@ -137,6 +137,7 @@ impl pallet_teebag::Config for Test { type MomentsPerDay = MomentsPerDay; type SetAdminOrigin = EnsureRoot; type MaxEnclaveIdentifier = ConstU32<1>; + type MaxAuthorizedEnclave = ConstU32<2>; } // This function basically just builds a genesis storage key/value store according to diff --git a/pallets/teebag/src/sgx_verify/collateral.rs b/pallets/teebag/src/sgx_verify/collateral.rs index 53f3c55af4..bf8db1b0ef 100644 --- a/pallets/teebag/src/sgx_verify/collateral.rs +++ b/pallets/teebag/src/sgx_verify/collateral.rs @@ -95,7 +95,12 @@ impl TcbLevelFull { pub fn is_valid(&self) -> bool { // A possible extension would be to also verify that the advisory_ids list is empty, // but I think this could also lead to all TcbLevels being invalid - self.tcb_status == "UpToDate" || self.tcb_status == "SWHardeningNeeded" + // + // Litentry: be more lenient with it + self.tcb_status == "UpToDate" || + self.tcb_status == "SWHardeningNeeded" || + self.tcb_status == "ConfigurationNeeded" || + self.tcb_status == "ConfigurationAndSWHardeningNeeded" } } diff --git a/pallets/teebag/src/sgx_verify/mod.rs b/pallets/teebag/src/sgx_verify/mod.rs index f1a98e751b..81236da078 100644 --- a/pallets/teebag/src/sgx_verify/mod.rs +++ b/pallets/teebag/src/sgx_verify/mod.rs @@ -267,8 +267,6 @@ pub struct SgxReportBody { impl SgxReportBody { pub fn sgx_build_mode(&self) -> SgxBuildMode { - #[cfg(test)] - println!("attributes flag : {:x}", self.attributes.flags); if self.attributes.flags & SGX_FLAGS_DEBUG == SGX_FLAGS_DEBUG { SgxBuildMode::Debug } else { @@ -545,9 +543,6 @@ pub fn verify_dcap_quote( let quote: DcapQuote = Decode::decode(&mut dcap_quote_clone).map_err(|_| "Failed to decode attestation report")?; - #[cfg(test)] - println!("{:?}", quote); - ensure!(quote.header.version == 3, "Only support for version 3"); ensure!(quote.header.attestation_key_type == 2, "Only support for ECDSA-256"); ensure!( @@ -643,10 +638,6 @@ pub fn verify_dcap_quote( pub fn verify_ias_report(cert_der: &[u8]) -> Result { // Before we reach here, the runtime already verified the extrinsic is properly signed by the // extrinsic sender Hence, we skip: EphemeralKey::try_from(cert)?; - - #[cfg(test)] - println!("verifyRA: start verifying RA cert"); - let cert = CertDer(cert_der); let netscape = NetscapeComment::try_from(cert)?; let sig_cert_der = webpki::types::CertificateDer::from(netscape.sig_cert.as_slice()); @@ -691,9 +682,6 @@ fn parse_report(netscape: &NetscapeComment) -> Result { .try_into() .map_err(|_| "Error converting report.timestamp to u64")?; - #[cfg(test)] - println!("verifyRA attestation timestamp [unix epoch]: {}", ra_timestamp); - // get quote status (mandatory field) let ra_status = match &attn_report["isvEnclaveQuoteStatus"] { Value::String(quote_status) => match quote_status.as_ref() { @@ -706,32 +694,18 @@ fn parse_report(netscape: &NetscapeComment) -> Result { _ => return Err("Failed to fetch isvEnclaveQuoteStatus from attestation report"), }; - #[cfg(test)] - println!("verifyRA attestation status is: {:?}", ra_status); // parse quote body if let Value::String(quote_raw) = &attn_report["isvEnclaveQuoteBody"] { let quote = match base64::decode(quote_raw) { Ok(q) => q, Err(_) => return Err("Quote Decoding Error"), }; - #[cfg(test)] - println!("Quote read. len={}", quote.len()); // TODO: lack security check here let sgx_quote: SgxQuote = match Decode::decode(&mut "e[..]) { Ok(q) => q, Err(_) => return Err("could not decode quote"), }; - #[cfg(test)] - { - println!("sgx quote version = {}", sgx_quote.version); - println!("sgx quote signature type = {}", sgx_quote.sign_type); - //println!("sgx quote report_data = {:?}", sgx_quote.report_body.report_data.d[..32]); - println!("sgx quote mr_enclave = {:x?}", sgx_quote.report_body.mr_enclave); - println!("sgx quote mr_signer = {:x?}", sgx_quote.report_body.mr_signer); - println!("sgx quote report_data = {:x?}", sgx_quote.report_body.report_data.d.to_vec()); - } - let mut xt_signer_array = [0u8; 32]; xt_signer_array.copy_from_slice(&sgx_quote.report_body.report_data.d[..32]); Ok(SgxReport { @@ -754,16 +728,8 @@ pub fn verify_signature( signature_algorithm: &dyn webpki::types::SignatureVerificationAlgorithm, ) -> Result<(), &'static str> { match entity_cert.verify_signature(signature_algorithm, data, signature) { - Ok(()) => { - #[cfg(test)] - println!("IAS signature is valid"); - Ok(()) - }, - Err(_e) => { - #[cfg(test)] - println!("RSA Signature ERROR: {}", _e); - Err("bad signature") - }, + Ok(()) => Ok(()), + Err(_e) => Err("bad signature"), } } @@ -780,16 +746,8 @@ pub fn verify_server_cert( webpki::KeyUsage::server_auth(), None, ) { - Ok(()) => { - #[cfg(test)] - println!("CA is valid"); - Ok(()) - }, - Err(_e) => { - #[cfg(test)] - println!("CA ERROR: {}", _e); - Err("CA verification failed") - }, + Ok(()) => Ok(()), + Err(_e) => Err("CA verification failed"), } } diff --git a/pallets/teebag/src/sgx_verify/netscape_comment.rs b/pallets/teebag/src/sgx_verify/netscape_comment.rs index 3d39d22e19..e5791e2e56 100644 --- a/pallets/teebag/src/sgx_verify/netscape_comment.rs +++ b/pallets/teebag/src/sgx_verify/netscape_comment.rs @@ -25,8 +25,6 @@ impl<'a> TryFrom> for NetscapeComment<'a> { offset += 12; // 11 + TAG (0x04) - #[cfg(test)] - println!("netscape"); // Obtain Netscape Comment length let len = length_from_raw_data(cert_der, &mut offset)?; // Obtain Netscape Comment diff --git a/pallets/teebag/src/tests.rs b/pallets/teebag/src/tests.rs index 4aaee360b7..9c1359f7de 100644 --- a/pallets/teebag/src/tests.rs +++ b/pallets/teebag/src/tests.rs @@ -18,8 +18,8 @@ #![allow(dead_code, unused_imports)] use crate::{ - mock::*, test_util::*, AttestationType, DcapProvider, Enclave, EnclaveRegistry, Error, - Event as TeebagEvent, ScheduledEnclave, SgxBuildMode, WorkerType, H256, + mock::*, test_util::*, AttestationType, AuthorizedEnclave, DcapProvider, Enclave, + EnclaveRegistry, Error, Event as TeebagEvent, SgxBuildMode, WorkerType, H256, }; use frame_support::{assert_noop, assert_ok}; use hex_literal::hex; @@ -78,14 +78,14 @@ fn register_tcb_info() { // ===================================================== // Unittest in `Development` mode, where: // - AttestationType::Ignore is possible -// - No scheduled enclave check +// - No authorized enclave check // - No sgx_build_mode check // ===================================================== #[test] -fn register_enclave_dev_works_with_no_scheduled_enclave() { +fn register_enclave_dev_works_with_no_authorized_enclave() { new_test_ext(true).execute_with(|| { - // it works with no entry in scheduled_enclave + // it works with no entry in authorized_enclave assert_ok!(Teebag::register_enclave( RuntimeOrigin::signed(alice()), Default::default(), @@ -102,10 +102,9 @@ fn register_enclave_dev_works_with_no_scheduled_enclave() { assert_eq!(Teebag::enclave_count(WorkerType::Identity), 1); assert_eq!(Teebag::enclave_count(WorkerType::BitAcross), 0); assert_eq!(EnclaveRegistry::::get(alice()).unwrap(), enclave); - assert_eq!( - ScheduledEnclave::::get((WorkerType::default(), 0)).unwrap().to_vec(), - TEST4_MRENCLAVE.to_vec() - ); + let authorized_enclave = AuthorizedEnclave::::get(WorkerType::default()); + assert_eq!(authorized_enclave.len(), 1); + assert_eq!(authorized_enclave.first().unwrap(), TEST4_MRENCLAVE.as_ref()); }) } @@ -206,7 +205,7 @@ fn register_dcap_enclave_works() { URL.to_vec(), None, None, - AttestationType::Dcap(DcapProvider::Integritee) + AttestationType::Dcap(DcapProvider::Intel) )); assert_eq!(Teebag::enclave_count(WorkerType::Identity), 1); assert_eq!(Teebag::enclave_registry(&signer).unwrap().last_seen_timestamp, VALID_TIMESTAMP); @@ -215,6 +214,58 @@ fn register_dcap_enclave_works() { }) } +const DCAP_QUOTE: &str = "030002000000000009000e00939a7233f79c4ca9940a0db3957f0607843bf40b9a0f12a878f1142ded7b9c29000000000b0c0218ffff0400000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000e700000000000000e31ec6238a622fa6db93cfc7502c78b62aa23f74f2b7d0cb7a105a11f6b5e931000000000000000000000000000000000000000000000000000000000000000013d77a368135bbb449b56576f5fa46f96774afa540a59147fa5eb4fd9a1c6cd2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006f93d0e68224f71745321b00d4c02119fdcc6d7a5caad051f664a0484cc9f56d0000000000000000000000000000000000000000000000000000000000000000441000007f65a0a8dcfac917056c6fffd0d4c48f25707f0591efab17f73fbd7121db48a4c006643aaaa997093a89b6d010a372cfda9a2849462c8c3649848b4ff0f989def0c4025ecf251d0de3745f9e7743e45d3a13afa5f3d03c70ebbb547109ee4f6c21c97d85eacf1eab4798e92a30f3955773bc010dfc99c534380853707cdcf4f50b0c0218ffff0400000000000000000000000000000000000000000000000000000000000000000000000000000000001500000000000000e700000000000000192aa50ce1c0cef03ccf89e7b5b16b0d7978f5c2b1edcf774d87702e8154d8bf00000000000000000000000000000000000000000000000000000000000000008c4f5775d796503e96137f77c68a829a0056ac8ded70140b081b094490c57bff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b3aa0f75e102c73b080a746df8573700dc799dcd1e698235e6afa52a4907bad90000000000000000000000000000000000000000000000000000000000000000309fff9db713fdc6529a2182e025731ff65a6f013eb166a2a79ef19c18d28f61f6f24ffef9d528bf6b9b84577e17916eb219a347d90200b74bca9c046772e9702000000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f0500dc0d00002d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949456a6a4343424453674177494241674956414c6b4359352f4166756e41584a7566334432304c57444c4c4a61464d416f4743437147534d343942414d430a4d484578497a416842674e5642414d4d476b6c756447567349464e48574342515130736755484a765932567a6332397949454e424d526f77474159445651514b0a4442464a626e526c6243424462334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e560a4241674d416b4e424d517377435159445651514745774a56557a4165467730794e4441334d4459794d6a4d324d4464614677307a4d5441334d4459794d6a4d320a4d4464614d484178496a416742674e5642414d4d47556c756447567349464e4857434251513073675132567964476c6d61574e6864475578476a415942674e560a42416f4d45556c756447567349454e76636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b470a413155454341774351304578437a414a42674e5642415954416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741450a613776706e38486d32654668386b3979795a73516270614a6b4f71764f4c732b472f63764779344e34567143536e4d6c4130367051506d3376787559587a4f6b0a613247382b69787663415979556a745037354a557a364f434171677767674b6b4d42384741315564497751594d426141464e446f71747031312f6b75535265590a504873555a644456386c6c4e4d477747413155644877526c4d474d77596142666f463247573268306448427a4f693876595842704c6e527964584e305a57527a0a5a584a3261574e6c63793570626e526c6243356a62323076633264344c324e6c636e52705a6d6c6a5958527062323476646a517663474e7259334a7350324e680a5058427962324e6c63334e7663695a6c626d4e765a476c755a7a316b5a584977485159445652304f424259454642616e30456848464431556573414b4c58572f0a70382b54685a627a4d41344741315564447745422f775145417749477744414d42674e5648524d4241663845416a41414d4949423141594a4b6f5a496876684e0a415130424249494278544343416345774867594b4b6f5a496876684e415130424151515164474b4f704e37624b782b31306872386d6b786855544343415751470a43697147534962345451454e41514977676746554d42414743797147534962345451454e415149424167454c4d42414743797147534962345451454e415149430a4167454c4d42414743797147534962345451454e41514944416745434d42414743797147534962345451454e41514945416745434d42454743797147534962340a5451454e41514946416749412f7a415142677371686b69472b45304244514543426749424154415142677371686b69472b4530424451454342774942414441510a42677371686b69472b45304244514543434149424144415142677371686b69472b45304244514543435149424144415142677371686b69472b453042445145430a436749424144415142677371686b69472b45304244514543437749424144415142677371686b69472b45304244514543444149424144415142677371686b69470a2b45304244514543445149424144415142677371686b69472b45304244514543446749424144415142677371686b69472b4530424451454344774942414441510a42677371686b69472b45304244514543454149424144415142677371686b69472b45304244514543455149424454416642677371686b69472b453042445145430a4567515143777343417638424141414141414141414141414144415142676f71686b69472b45304244514544424149414144415542676f71686b69472b4530420a44514545424159416f476352414141774477594b4b6f5a496876684e4151304242516f424144414b42676771686b6a4f5051514441674e4941444246416945410a69467264455347686a74756a4745636f483766542f7976735a4862644d38492b5550746e413342674536454349416e6d597a6f4b596b5839412b4731424843770a75456d34517447776b65715a2f44766e6355456d51326b580a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436d444343416a36674177494241674956414e446f71747031312f6b7553526559504873555a644456386c6c4e4d416f4743437147534d343942414d430a4d476778476a415942674e5642414d4d45556c756447567349464e48574342536232393049454e424d526f77474159445651514b4442464a626e526c624342440a62334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e424d5173770a435159445651514745774a56557a4165467730784f4441314d6a45784d4455774d5442614677307a4d7a41314d6a45784d4455774d5442614d484578497a41680a42674e5642414d4d476b6c756447567349464e48574342515130736755484a765932567a6332397949454e424d526f77474159445651514b4442464a626e526c0a6243424462334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e420a4d517377435159445651514745774a56557a425a4d424d4742797147534d34394167454743437147534d34394177454841304941424c39712b4e4d7032494f670a74646c31626b2f75575a352b5447516d38614369387a373866732b664b435133642b75447a586e56544154325a68444369667949754a77764e33774e427039690a484253534d4a4d4a72424f6a6762737767626777487759445652306a42426777466f4155496d554d316c71644e496e7a6737535655723951477a6b6e427177770a556759445652306642457377535442486f45576751345a426148523063484d364c79396a5a584a3061575a70593246305a584d7564484a316333526c5a484e6c0a636e5a705932567a4c6d6c75644756734c6d4e766253394a626e526c62464e4857464a76623352445153356b5a584977485159445652304f42425945464e446f0a71747031312f6b7553526559504873555a644456386c6c4e4d41344741315564447745422f77514541774942426a415342674e5648524d4241663845434441470a4151482f416745414d416f4743437147534d343942414d43413067414d4555434951434a6754627456714f795a316d336a716941584d365159613672357357530a34792f4737793875494a4778647749675271507642534b7a7a516167424c517135733541373070646f6961524a387a2f3075447a344e675639316b3d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a6737535655723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a55723951477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b533943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c72486f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a00"; + +#[test] +fn register_dcap_enclave2_works() { + // the data comes from real quote generated on our host + new_test_ext(true).execute_with(|| { + Timestamp::set_timestamp(1720308602000); + + let quoting_enclave = br#"{"id":"QE","version":2,"issueDate":"2024-07-06T21:44:35Z","nextUpdate":"2024-08-05T21:44:35Z","tcbEvaluationDataNumber":16,"miscselect":"00000000","miscselectMask":"FFFFFFFF","attributes":"11000000000000000000000000000000","attributesMask":"FBFFFFFFFFFFFFFF0000000000000000","mrsigner":"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF","isvprodid":1,"tcbLevels":[{"tcb":{"isvsvn":8},"tcbDate":"2023-08-09T00:00:00Z","tcbStatus":"UpToDate"},{"tcb":{"isvsvn":6},"tcbDate":"2021-11-10T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00615"]},{"tcb":{"isvsvn":5},"tcbDate":"2020-11-11T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00477","INTEL-SA-00615"]},{"tcb":{"isvsvn":4},"tcbDate":"2019-11-13T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00334","INTEL-SA-00477","INTEL-SA-00615"]},{"tcb":{"isvsvn":2},"tcbDate":"2019-05-15T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00219","INTEL-SA-00293","INTEL-SA-00334","INTEL-SA-00477","INTEL-SA-00615"]},{"tcb":{"isvsvn":1},"tcbDate":"2018-08-15T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00202","INTEL-SA-00219","INTEL-SA-00293","INTEL-SA-00334","INTEL-SA-00477","INTEL-SA-00615"]}]}"#; + let signature = hex!("86ff60fd0d914f08a88ff2b04284060f72eaa62d612cbfb9397e59b97aba74a05e429de8eaedd44db82fc5ee91113dbdd57e63e76d8ebcce83b1b9c557a9e0d9"); + let certificate_chain = hex!("2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d494943697a4343416a4b674177494241674955666a6943316674564b5570415359354668415070464a473939465577436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e5441784d466f58445449314d4455794d5445774e5441784d466f77624445654d4277470a4131554541777756535735305a577767553064594946524451694254615764756157356e4d526f77474159445651514b4442464a626e526c6243424462334a770a62334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e424d517377435159440a5651514745774a56557a425a4d424d4742797147534d34394167454743437147534d3439417745484130494142454e464738787a79645752664b3932626d47760a502b6d4168393150457956374a683646474a64356e644539614248375233453441377562726c682f7a4e3343347876706f6f75476c69724d62612b57326c6a750a7970616a6762557767624977487759445652306a42426777466f4155496d554d316c71644e496e7a6737535655723951477a6b6e4271777755675944565230660a42457377535442486f45576751345a426148523063484d364c79396a5a584a3061575a70593246305a584d7564484a316333526c5a484e6c636e5a705932567a0a4c6d6c75644756734c6d4e766253394a626e526c62464e4857464a76623352445153356b5a584977485159445652304f42425945464834346774583756536c4b0a51456d4f5259514436525352766652564d41344741315564447745422f775145417749477744414d42674e5648524d4241663845416a41414d416f47434371470a534d343942414d43413063414d4551434942394338774f414e2f496d784474474143563234364b63716a61675a4f52306b7963747942727347474a564169416a0a667462724e47734755385948323131645269594e6f50507531395a702f7a65384a6d68756a42306f42773d3d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a6737535655723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a55723951477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b533943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c72486f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a00"); + + let pubkey: Vec = hex::decode("6f93d0e68224f71745321b00d4c02119fdcc6d7a5caad051f664a0484cc9f56d").unwrap(); + let dcap = hex::decode(DCAP_QUOTE).unwrap(); + let signer: AccountId = pubkey.as_slice().try_into().unwrap(); + + assert_ok!(Teebag::register_quoting_enclave( + RuntimeOrigin::signed(signer.clone()), + quoting_enclave.to_vec(), + signature.to_vec(), + certificate_chain.to_vec(), + )); + + // register tcb + let tcb_info = br#"{"id":"SGX","version":3,"issueDate":"2024-07-06T22:21:41Z","nextUpdate":"2024-08-05T22:21:41Z","fmspc":"00A067110000","pceId":"0000","tcbType":0,"tcbEvaluationDataNumber":16,"tcbLevels":[{"tcb":{"sgxtcbcomponents":[{"svn":11},{"svn":11},{"svn":2},{"svn":2},{"svn":255},{"svn":1},{"svn":12},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":13},"tcbDate":"2023-08-09T00:00:00Z","tcbStatus":"SWHardeningNeeded","advisoryIDs":["INTEL-SA-00615"]},{"tcb":{"sgxtcbcomponents":[{"svn":11},{"svn":11},{"svn":2},{"svn":2},{"svn":255},{"svn":1},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":13},"tcbDate":"2023-08-09T00:00:00Z","tcbStatus":"ConfigurationAndSWHardeningNeeded","advisoryIDs":["INTEL-SA-00289","INTEL-SA-00615"]},{"tcb":{"sgxtcbcomponents":[{"svn":10},{"svn":10},{"svn":2},{"svn":2},{"svn":255},{"svn":1},{"svn":12},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":13},"tcbDate":"2023-02-15T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00828","INTEL-SA-00289","INTEL-SA-00615"]},{"tcb":{"sgxtcbcomponents":[{"svn":10},{"svn":10},{"svn":2},{"svn":2},{"svn":255},{"svn":1},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":13},"tcbDate":"2023-02-15T00:00:00Z","tcbStatus":"OutOfDateConfigurationNeeded","advisoryIDs":["INTEL-SA-00289","INTEL-SA-00828","INTEL-SA-00615"]},{"tcb":{"sgxtcbcomponents":[{"svn":9},{"svn":9},{"svn":2},{"svn":2},{"svn":255},{"svn":1},{"svn":12},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":13},"tcbDate":"2022-11-09T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00657","INTEL-SA-00767","INTEL-SA-00289","INTEL-SA-00828","INTEL-SA-00615"]},{"tcb":{"sgxtcbcomponents":[{"svn":9},{"svn":9},{"svn":2},{"svn":2},{"svn":255},{"svn":1},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":13},"tcbDate":"2022-11-09T00:00:00Z","tcbStatus":"OutOfDateConfigurationNeeded","advisoryIDs":["INTEL-SA-00289","INTEL-SA-00657","INTEL-SA-00767","INTEL-SA-00828","INTEL-SA-00615"]},{"tcb":{"sgxtcbcomponents":[{"svn":5},{"svn":5},{"svn":2},{"svn":2},{"svn":255},{"svn":1},{"svn":4},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":11},"tcbDate":"2021-11-10T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00614","INTEL-SA-00617","INTEL-SA-00289","INTEL-SA-00657","INTEL-SA-00767","INTEL-SA-00828","INTEL-SA-00615"]},{"tcb":{"sgxtcbcomponents":[{"svn":5},{"svn":5},{"svn":2},{"svn":2},{"svn":255},{"svn":1},{"svn":4},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":10},"tcbDate":"2020-11-11T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00289","INTEL-SA-00614","INTEL-SA-00617","INTEL-SA-00657","INTEL-SA-00767","INTEL-SA-00828","INTEL-SA-00615"]},{"tcb":{"sgxtcbcomponents":[{"svn":5},{"svn":5},{"svn":2},{"svn":2},{"svn":255},{"svn":1},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":11},"tcbDate":"2021-11-10T00:00:00Z","tcbStatus":"OutOfDateConfigurationNeeded","advisoryIDs":["INTEL-SA-00289","INTEL-SA-00614","INTEL-SA-00617","INTEL-SA-00657","INTEL-SA-00767","INTEL-SA-00828","INTEL-SA-00615"]},{"tcb":{"sgxtcbcomponents":[{"svn":5},{"svn":5},{"svn":2},{"svn":2},{"svn":255},{"svn":1},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":10},"tcbDate":"2020-11-11T00:00:00Z","tcbStatus":"OutOfDateConfigurationNeeded","advisoryIDs":["INTEL-SA-00477","INTEL-SA-00289","INTEL-SA-00614","INTEL-SA-00617","INTEL-SA-00657","INTEL-SA-00767","INTEL-SA-00828","INTEL-SA-00615"]},{"tcb":{"sgxtcbcomponents":[{"svn":5},{"svn":5},{"svn":2},{"svn":2},{"svn":255},{"svn":1},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0},{"svn":0}],"pcesvn":5},"tcbDate":"2018-01-04T00:00:00Z","tcbStatus":"OutOfDate","advisoryIDs":["INTEL-SA-00106","INTEL-SA-00115","INTEL-SA-00135","INTEL-SA-00203","INTEL-SA-00220","INTEL-SA-00233","INTEL-SA-00270","INTEL-SA-00293","INTEL-SA-00320","INTEL-SA-00329","INTEL-SA-00381","INTEL-SA-00389","INTEL-SA-00477","INTEL-SA-00289","INTEL-SA-00614","INTEL-SA-00617","INTEL-SA-00657","INTEL-SA-00767","INTEL-SA-00828","INTEL-SA-00615"]}]}"#; + let signature = hex!("7173d497ca3dcc87c190d1f03e7c3ef04e253f81ac90563fd90131d49df50216f60d0a1369b103fda9720a91d9963afabde6aade0ded3646b52727a42dce210c"); + let certificate_chain = hex!("2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d494943697a4343416a4b674177494241674955666a6943316674564b5570415359354668415070464a473939465577436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e5441784d466f58445449314d4455794d5445774e5441784d466f77624445654d4277470a4131554541777756535735305a577767553064594946524451694254615764756157356e4d526f77474159445651514b4442464a626e526c6243424462334a770a62334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e424d517377435159440a5651514745774a56557a425a4d424d4742797147534d34394167454743437147534d3439417745484130494142454e464738787a79645752664b3932626d47760a502b6d4168393150457956374a683646474a64356e644539614248375233453441377562726c682f7a4e3343347876706f6f75476c69724d62612b57326c6a750a7970616a6762557767624977487759445652306a42426777466f4155496d554d316c71644e496e7a6737535655723951477a6b6e4271777755675944565230660a42457377535442486f45576751345a426148523063484d364c79396a5a584a3061575a70593246305a584d7564484a316333526c5a484e6c636e5a705932567a0a4c6d6c75644756734c6d4e766253394a626e526c62464e4857464a76623352445153356b5a584977485159445652304f42425945464834346774583756536c4b0a51456d4f5259514436525352766652564d41344741315564447745422f775145417749477744414d42674e5648524d4241663845416a41414d416f47434371470a534d343942414d43413063414d4551434942394338774f414e2f496d784474474143563234364b63716a61675a4f52306b7963747942727347474a564169416a0a667462724e47734755385948323131645269594e6f50507531395a702f7a65384a6d68756a42306f42773d3d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a6737535655723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a55723951477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b533943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c72486f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a00"); + + assert_ok!(Teebag::register_tcb_info( + RuntimeOrigin::signed(signer.clone()), + tcb_info.to_vec(), + signature.to_vec(), + certificate_chain.to_vec(), + )); + + assert_ok!(Teebag::register_enclave( + RuntimeOrigin::signed(signer.clone()), + WorkerType::Identity, + Default::default(), + dcap, + URL.to_vec(), + None, + None, + AttestationType::Dcap(DcapProvider::Intel) + )); + assert_eq!(Teebag::enclave_count(WorkerType::Identity), 1); + assert_eq!(Teebag::enclave_registry(&signer).unwrap().last_seen_timestamp, 1720308602000); + assert_ok!(Teebag::unregister_enclave(RuntimeOrigin::signed(signer))); + assert_eq!(Teebag::enclave_count(WorkerType::Identity), 0); + }) +} + // ===================================================== // Unittest in `Production` mode // ===================================================== @@ -222,10 +273,9 @@ fn register_dcap_enclave_works() { #[test] fn register_enclave_prod_works_with_sgx_build_mode_debug() { new_test_ext(false).execute_with(|| { - assert_ok!(Teebag::set_scheduled_enclave( + assert_ok!(Teebag::force_add_authorized_enclave( RuntimeOrigin::signed(alice()), WorkerType::Identity, - 0, TEST4_MRENCLAVE )); @@ -257,10 +307,9 @@ fn register_enclave_prod_works_with_sgx_build_mode_debug() { #[test] fn register_enclave_prod_works_with_sgx_build_mode_production() { new_test_ext(false).execute_with(|| { - assert_ok!(Teebag::set_scheduled_enclave( + assert_ok!(Teebag::force_add_authorized_enclave( RuntimeOrigin::signed(alice()), WorkerType::Identity, - 0, TEST8_MRENCLAVE )); @@ -286,6 +335,15 @@ fn register_enclave_prod_works_with_sgx_build_mode_production() { assert_eq!(Teebag::enclave_count(WorkerType::Identity), 1); assert_eq!(Teebag::enclave_count(WorkerType::BitAcross), 0); assert_eq!(EnclaveRegistry::::get(signer8).unwrap(), enclave); + + // remove authorized enclave should remove enclave too + assert_ok!(Teebag::force_remove_authorized_enclave( + RuntimeOrigin::signed(alice()), + WorkerType::Identity, + TEST8_MRENCLAVE + )); + assert_eq!(Teebag::authorized_enclave(WorkerType::Identity).len(), 0); + assert_eq!(Teebag::enclave_count(WorkerType::Identity), 0); }) } @@ -309,7 +367,7 @@ fn register_enclave_prod_fails_with_wrong_attestation_type() { } #[test] -fn register_enclave_prod_fails_with_no_scheduled_enclave() { +fn register_enclave_prod_fails_with_no_authorized_enclave() { new_test_ext(false).execute_with(|| { Timestamp::set_timestamp(TEST4_TIMESTAMP); let signer = get_signer(TEST4_SIGNER_PUB); @@ -324,7 +382,7 @@ fn register_enclave_prod_fails_with_no_scheduled_enclave() { None, AttestationType::Ias, ), - Error::::EnclaveNotInSchedule + Error::::EnclaveNotAuthorized ); }) } @@ -332,25 +390,42 @@ fn register_enclave_prod_fails_with_no_scheduled_enclave() { #[test] fn register_enclave_prod_fails_with_max_limit_reached() { new_test_ext(false).execute_with(|| { - ScheduledEnclave::::insert((WorkerType::BitAcross, 0), TEST5_MRENCLAVE); - ScheduledEnclave::::insert((WorkerType::BitAcross, 1), TEST6_MRENCLAVE); - ScheduledEnclave::::insert((WorkerType::Identity, 0), TEST5_MRENCLAVE); - ScheduledEnclave::::insert((WorkerType::Identity, 1), TEST6_MRENCLAVE); + assert_ok!(Teebag::force_add_authorized_enclave( + RuntimeOrigin::signed(alice()), + WorkerType::Identity, + TEST4_MRENCLAVE + )); + assert_ok!(Teebag::force_add_authorized_enclave( + RuntimeOrigin::signed(alice()), + WorkerType::Identity, + TEST6_MRENCLAVE + )); + assert_ok!(Teebag::force_add_authorized_enclave( + RuntimeOrigin::signed(alice()), + WorkerType::BitAcross, + TEST4_MRENCLAVE + )); + assert_ok!(Teebag::force_add_authorized_enclave( + RuntimeOrigin::signed(alice()), + WorkerType::BitAcross, + TEST6_MRENCLAVE + )); - let signer5: AccountId32 = get_signer(TEST5_SIGNER_PUB); + let signer4: AccountId32 = get_signer(TEST4_SIGNER_PUB); let signer6: AccountId32 = get_signer(TEST6_SIGNER_PUB); - Timestamp::set_timestamp(TEST5_TIMESTAMP); + Timestamp::set_timestamp(TEST4_TIMESTAMP); assert_ok!(Teebag::register_enclave( - RuntimeOrigin::signed(signer5.clone()), + RuntimeOrigin::signed(signer4.clone()), WorkerType::BitAcross, Default::default(), - TEST5_CERT.to_vec(), + TEST4_CERT.to_vec(), URL.to_vec(), None, None, AttestationType::Ias, )); + Timestamp::set_timestamp(TEST6_TIMESTAMP); assert_noop!( Teebag::register_enclave( @@ -367,13 +442,13 @@ fn register_enclave_prod_fails_with_max_limit_reached() { ); // re-register them as WorkerType::Identity is not allowed - Timestamp::set_timestamp(TEST5_TIMESTAMP); + Timestamp::set_timestamp(TEST4_TIMESTAMP); assert_noop!( Teebag::register_enclave( - RuntimeOrigin::signed(signer5.clone()), + RuntimeOrigin::signed(signer4.clone()), WorkerType::Identity, Default::default(), - TEST5_CERT.to_vec(), + TEST4_CERT.to_vec(), URL.to_vec(), None, None, @@ -383,13 +458,13 @@ fn register_enclave_prod_fails_with_max_limit_reached() { ); // remove and re-register it should work - assert_ok!(Teebag::force_remove_enclave(RuntimeOrigin::signed(alice()), signer5.clone(),)); + assert_ok!(Teebag::force_remove_enclave(RuntimeOrigin::signed(alice()), signer4.clone(),)); assert_ok!(Teebag::register_enclave( - RuntimeOrigin::signed(signer5), + RuntimeOrigin::signed(signer4), WorkerType::Identity, Default::default(), - TEST5_CERT.to_vec(), + TEST4_CERT.to_vec(), URL.to_vec(), None, None, diff --git a/pallets/teebag/src/types.rs b/pallets/teebag/src/types.rs index c14c5f475a..6e0c283ec5 100644 --- a/pallets/teebag/src/types.rs +++ b/pallets/teebag/src/types.rs @@ -54,8 +54,8 @@ pub enum OperationalMode { #[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub enum DcapProvider { #[default] - MAA, Intel, + MAA, Local, Integritee, } diff --git a/pallets/vc-management/src/mock.rs b/pallets/vc-management/src/mock.rs index 5d4517e2d5..0fe081980a 100644 --- a/pallets/vc-management/src/mock.rs +++ b/pallets/vc-management/src/mock.rs @@ -159,6 +159,7 @@ impl pallet_teebag::Config for Test { type MomentsPerDay = MomentsPerDay; type SetAdminOrigin = EnsureRoot; type MaxEnclaveIdentifier = ConstU32<3>; + type MaxAuthorizedEnclave = ConstU32<3>; } impl pallet_group::Config for Test { diff --git a/primitives/core/src/assertion/dynamic.rs b/primitives/core/src/assertion/dynamic.rs new file mode 100644 index 0000000000..7a7a1054ef --- /dev/null +++ b/primitives/core/src/assertion/dynamic.rs @@ -0,0 +1,32 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_core::H160; +use sp_runtime::{traits::ConstU32, BoundedVec}; + +pub type DynamicContractParams = BoundedVec>; + +#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, MaxEncodedLen, TypeInfo)] +pub struct DynamicParams { + // smart contract code identifier + pub smart_contract_id: H160, + // abi encoded smart contract params + pub smart_contract_params: Option, + // true to return contract log + pub return_log: bool, +} diff --git a/primitives/core/src/assertion/mod.rs b/primitives/core/src/assertion/mod.rs index 4a6b142b61..ce73ca6ba8 100644 --- a/primitives/core/src/assertion/mod.rs +++ b/primitives/core/src/assertion/mod.rs @@ -51,11 +51,13 @@ use web3_nft::Web3NftType; pub mod web3_token; use web3_token::Web3TokenType; -use crate::{AccountId, DynamicParams, ParameterString}; +pub mod dynamic; +use dynamic::DynamicParams; + +use crate::{AccountId, ParameterString}; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_core::H160; use sp_std::{vec, vec::Vec}; #[rustfmt::skip] @@ -138,9 +140,18 @@ pub enum Assertion { NftHolder(Web3NftType), #[codec(index = 27)] - Dynamic(H160, DynamicParams) // smart contract code identifier, abi encoded smart contract params + Dynamic(DynamicParams) } +const A8_SUPPORTED_NETWORKS: [Web3Network; 6] = [ + Web3Network::Polkadot, + Web3Network::Kusama, + Web3Network::Litentry, + Web3Network::Litmus, + Web3Network::Khala, + Web3Network::Ethereum, +]; + impl Assertion { // Given an assertion enum type, retrieve the supported web3 networks. // So we limit the network types on the assertion definition level. @@ -162,7 +173,11 @@ impl Assertion { Self::VIP3MembershipCard(..) | Self::WeirdoGhostGangHolder => vec![Web3Network::Ethereum], // total tx over `networks` - Self::A8(network) => network.to_vec(), + Self::A8(networks) => networks + .into_iter() + .filter(|network| A8_SUPPORTED_NETWORKS.contains(*network)) + .cloned() + .collect::>(), // Achainable Assertions Self::Achainable(arg) => arg.chains(), // OneBlock Assertion diff --git a/primitives/core/src/assertion/platform_user.rs b/primitives/core/src/assertion/platform_user.rs index fe85afbeb3..e5a5ebc3b1 100644 --- a/primitives/core/src/assertion/platform_user.rs +++ b/primitives/core/src/assertion/platform_user.rs @@ -23,15 +23,17 @@ use crate::assertion::network::{all_evm_web3networks, Web3Network}; #[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, MaxEncodedLen, TypeInfo)] pub enum PlatformUserType { #[codec(index = 0)] - KaratDaoUser, + KaratDao, #[codec(index = 1)] - MagicCraftStakingUser, + MagicCraftStaking, + #[codec(index = 2)] + DarenMarket, } impl PlatformUserType { pub fn get_supported_networks(&self) -> Vec { match self { - Self::KaratDaoUser | Self::MagicCraftStakingUser => all_evm_web3networks(), + Self::KaratDao | Self::MagicCraftStaking | Self::DarenMarket => all_evm_web3networks(), } } } diff --git a/primitives/core/src/assertion/web3_nft.rs b/primitives/core/src/assertion/web3_nft.rs index d51b30ec3b..606d88a1cd 100644 --- a/primitives/core/src/assertion/web3_nft.rs +++ b/primitives/core/src/assertion/web3_nft.rs @@ -26,13 +26,18 @@ pub enum Web3NftType { WeirdoGhostGang, #[codec(index = 1)] Club3Sbt, + #[codec(index = 2)] + MFan, + #[codec(index = 3)] + Mvp, } impl Web3NftType { pub fn get_supported_networks(&self) -> Vec { match self { - Self::WeirdoGhostGang => vec![Web3Network::Ethereum], + Self::WeirdoGhostGang | Self::Mvp => vec![Web3Network::Ethereum], Self::Club3Sbt => vec![Web3Network::Bsc, Web3Network::Polygon, Web3Network::Arbitrum], + Self::MFan => vec![Web3Network::Polygon], } } } diff --git a/primitives/core/src/assertion/web3_token.rs b/primitives/core/src/assertion/web3_token.rs index eef2fad103..3209a9f130 100644 --- a/primitives/core/src/assertion/web3_token.rs +++ b/primitives/core/src/assertion/web3_token.rs @@ -102,6 +102,10 @@ pub enum Web3TokenType { Inj, #[codec(index = 39)] Bean, + #[codec(index = 40)] + An, + #[codec(index = 41)] + Tuna, } impl Web3TokenType { @@ -137,6 +141,7 @@ impl Web3TokenType { Self::Atom => vec![Web3Network::Ethereum, Web3Network::Bsc, Web3Network::Polygon], Self::Cro => vec![Web3Network::Ethereum, Web3Network::Solana], Self::Bean => vec![Web3Network::Bsc, Web3Network::Combo], + Self::An => vec![Web3Network::Bsc], _ => vec![Web3Network::Ethereum], } } diff --git a/primitives/core/src/error.rs b/primitives/core/src/error.rs index 4360f364d4..a4eb7f8ba4 100644 --- a/primitives/core/src/error.rs +++ b/primitives/core/src/error.rs @@ -131,13 +131,9 @@ pub enum IMPError { DeactivateIdentityFailed(ErrorDetail), #[codec(index = 2)] ActivateIdentityFailed(ErrorDetail), - // scheduled encalve import error - #[codec(index = 3)] - ImportScheduledEnclaveFailed, - // should be unreached, but just to be on the safe side // we should classify the error if we ever get this - #[codec(index = 4)] + #[codec(index = 3)] UnclassifiedError(ErrorDetail), } diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 7136ce10c0..2fe01567de 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -38,8 +38,6 @@ pub use types::*; pub type ParameterString = BoundedVec>; -pub type DynamicParams = BoundedVec>; - /// Common types of parachains. mod types { use sp_runtime::{ diff --git a/runtime/litentry/Cargo.toml b/runtime/litentry/Cargo.toml index 4d9bc3dbfe..be600b960e 100644 --- a/runtime/litentry/Cargo.toml +++ b/runtime/litentry/Cargo.toml @@ -76,10 +76,12 @@ frame-system-benchmarking = { workspace = true, optional = true } core-primitives = { workspace = true } pallet-account-fix = { workspace = true } pallet-asset-manager = { workspace = true } +pallet-bitacross = { workspace = true } pallet-bridge = { workspace = true } pallet-bridge-transfer = { workspace = true } pallet-extrinsic-filter = { workspace = true } pallet-parachain-staking = { workspace = true } +pallet-teebag = { workspace = true } runtime-common = { workspace = true } fp-rpc = { workspace = true } @@ -124,6 +126,7 @@ runtime-benchmarks = [ "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-teebag/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", @@ -208,6 +211,8 @@ std = [ "pallet-bridge/std", "pallet-bridge-transfer/std", "pallet-extrinsic-filter/std", + "pallet-bitacross/std", + "pallet-teebag/std", "moonbeam-evm-tracer/std", "moonbeam-rpc-primitives-debug/std", "moonbeam-rpc-primitives-txpool/std", diff --git a/runtime/litentry/src/lib.rs b/runtime/litentry/src/lib.rs index f4081bfd44..cf71b5fb25 100644 --- a/runtime/litentry/src/lib.rs +++ b/runtime/litentry/src/lib.rs @@ -59,10 +59,11 @@ pub use core_primitives::{ opaque, AccountId, Amount, AssetId, Balance, BlockNumber, Hash, Header, Index, Signature, DAYS, HOURS, MINUTES, SLOT_DURATION, }; +use pallet_ethereum::TransactionStatus; pub use runtime_common::currency::*; use runtime_common::{ impl_runtime_transaction_payment_fees, prod_or_fast, BlockHashCount, BlockLength, - CouncilInstance, CouncilMembershipInstance, EnsureRootOrAllCouncil, + CouncilInstance, CouncilMembershipInstance, EnsureEnclaveSigner, EnsureRootOrAllCouncil, EnsureRootOrAllTechnicalCommittee, EnsureRootOrHalfCouncil, EnsureRootOrHalfTechnicalCommittee, EnsureRootOrTwoThirdsCouncil, EnsureRootOrTwoThirdsTechnicalCommittee, NegativeImbalance, RuntimeBlockWeights, SlowAdjustingFeeUpdate, TechnicalCommitteeInstance, @@ -70,7 +71,10 @@ use runtime_common::{ }; use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin}; -use pallet_ethereum::TransactionStatus; +// for TEE +pub use pallet_balances::Call as BalancesCall; +pub use pallet_teebag::{self, OperationalMode as TeebagOperationalMode}; + // Make the WASM binary available. #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); @@ -143,7 +147,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_name: create_runtime_str!("litentry-parachain"), authoring_version: 1, // same versioning-mechanism as polkadot: use last digit for minor updates - spec_version: 9181, + spec_version: 9184, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -842,6 +846,24 @@ impl pallet_extrinsic_filter::Config for Runtime { type WeightInfo = weights::pallet_extrinsic_filter::WeightInfo; } +parameter_types! { + pub const MomentsPerDay: u64 = 86_400_000; // [ms/d] +} + +impl pallet_teebag::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type MomentsPerDay = MomentsPerDay; + type SetAdminOrigin = EnsureRootOrHalfCouncil; + type MaxEnclaveIdentifier = ConstU32<3>; + type MaxAuthorizedEnclave = ConstU32<5>; +} + +impl pallet_bitacross::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type TEECallOrigin = EnsureEnclaveSigner; + type SetAdminOrigin = EnsureRootOrHalfCouncil; +} + impl runtime_common::BaseRuntimeRequirements for Runtime {} impl runtime_common::ParaRuntimeRequirements for Runtime {} @@ -912,6 +934,8 @@ construct_runtime! { BridgeTransfer: pallet_bridge_transfer = 61, ExtrinsicFilter: pallet_extrinsic_filter = 63, AssetManager: pallet_asset_manager = 64, + Teebag: pallet_teebag = 65, + Bitacross: pallet_bitacross = 66, // TMP AccountFix: pallet_account_fix = 254, @@ -977,7 +1001,11 @@ impl Contains for NormalModeFilter { // Balance RuntimeCall::Balances(_) | // AccountFix - RuntimeCall::AccountFix(_) + RuntimeCall::AccountFix(_) | + // TEE enclave management + RuntimeCall::Teebag(_) | + // Bitacross + RuntimeCall::Bitacross(_) ) } } diff --git a/runtime/litmus/src/lib.rs b/runtime/litmus/src/lib.rs index 1a0f782ff8..edebad9257 100644 --- a/runtime/litmus/src/lib.rs +++ b/runtime/litmus/src/lib.rs @@ -151,7 +151,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_name: create_runtime_str!("litmus-parachain"), authoring_version: 1, // same versioning-mechanism as polkadot: use last digit for minor updates - spec_version: 9181, + spec_version: 9184, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -796,6 +796,7 @@ impl pallet_teebag::Config for Runtime { type MomentsPerDay = MomentsPerDay; type SetAdminOrigin = EnsureRootOrHalfCouncil; type MaxEnclaveIdentifier = ConstU32<3>; + type MaxAuthorizedEnclave = ConstU32<5>; } impl pallet_bitacross::Config for Runtime { diff --git a/runtime/rococo/Cargo.toml b/runtime/rococo/Cargo.toml index 06744f1b93..ee0ea5faeb 100644 --- a/runtime/rococo/Cargo.toml +++ b/runtime/rococo/Cargo.toml @@ -87,6 +87,7 @@ pallet-extrinsic-filter = { workspace = true } pallet-group = { workspace = true } pallet-identity-management = { workspace = true } pallet-parachain-staking = { workspace = true } +pallet-score-staking = { workspace = true } pallet-teebag = { workspace = true } pallet-vc-management = { workspace = true } runtime-common = { workspace = true } @@ -161,6 +162,7 @@ runtime-benchmarks = [ "pallet-teebag/runtime-benchmarks", "pallet-vc-management/runtime-benchmarks", "pallet-account-fix/runtime-benchmarks", + "pallet-score-staking/runtime-benchmarks", ] std = [ "parity-scale-codec/std", @@ -245,6 +247,7 @@ std = [ "pallet-extrinsic-filter/std", "pallet-group/std", "pallet-identity-management/std", + "pallet-score-staking/std", "pallet-teebag/std", "pallet-vc-management/std", "pallet-account-fix/std", @@ -303,4 +306,5 @@ try-runtime = [ "pallet-account-fix/try-runtime", "pallet-bitacross/try-runtime", "pallet-bitacross-mimic/try-runtime", + "pallet-score-staking/try-runtime", ] diff --git a/runtime/rococo/src/lib.rs b/runtime/rococo/src/lib.rs index 9d4b77731f..4bafae5da9 100644 --- a/runtime/rococo/src/lib.rs +++ b/runtime/rococo/src/lib.rs @@ -245,7 +245,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_name: create_runtime_str!("rococo-parachain"), authoring_version: 1, // same versioning-mechanism as polkadot: use last digit for minor updates - spec_version: 9181, + spec_version: 9184, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -399,7 +399,8 @@ impl InstanceFilter for ProxyType { RuntimeCall::Democracy(..) | RuntimeCall::Council(..) | RuntimeCall::TechnicalCommittee(..) | - RuntimeCall::Treasury(..) + RuntimeCall::Treasury(..) | + RuntimeCall::DeveloperCommittee(..) ), } } @@ -1012,6 +1013,7 @@ impl pallet_teebag::Config for Runtime { type MomentsPerDay = MomentsPerDay; type SetAdminOrigin = EnsureRootOrHalfCouncil; type MaxEnclaveIdentifier = ConstU32<3>; + type MaxAuthorizedEnclave = ConstU32<5>; } impl pallet_identity_management::Config for Runtime { @@ -1032,6 +1034,7 @@ impl pallet_evm_assertions::Config for Runtime { type RuntimeEvent = RuntimeEvent; type AssertionId = H160; type ContractDevOrigin = pallet_collective::EnsureMember; + type TEECallOrigin = EnsureEnclaveSigner; } // Temporary for bitacross team to test @@ -1181,8 +1184,29 @@ impl pallet_ethereum::Config for Runtime { type ExtraDataLength = ConstU32<30>; } -impl runtime_common::BaseRuntimeRequirements for Runtime {} +parameter_types! { + pub const DefaultYearlyInflation: Perbill = Perbill::from_perthousand(5); +} +pub struct IdentityAccountIdConvert; + +impl pallet_score_staking::AccountIdConvert for IdentityAccountIdConvert { + fn convert(account: AccountId) -> ::AccountId { + account + } +} + +impl pallet_score_staking::Config for Runtime { + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type AccountIdConvert = IdentityAccountIdConvert; + type AdminOrigin = EnsureRootOrHalfCouncil; + type YearlyIssuance = ConstU128<{ 100_000_000 * UNIT }>; + type YearlyInflation = DefaultYearlyInflation; + type MaxScoreUserCount = ConstU32<1_000_000>; +} + +impl runtime_common::BaseRuntimeRequirements for Runtime {} impl runtime_common::ParaRuntimeRequirements for Runtime {} construct_runtime! { @@ -1264,6 +1288,7 @@ construct_runtime! { // Developer council DeveloperCommittee: pallet_collective:: = 73, DeveloperCommitteeMembership: pallet_membership:: = 74, + ScoreStaking: pallet_score_staking = 75, // TEE Teebag: pallet_teebag = 93, @@ -1290,7 +1315,8 @@ impl Contains for BaseCallFilter { RuntimeCall::ExtrinsicFilter(_) | RuntimeCall::Multisig(_) | RuntimeCall::Council(_) | - RuntimeCall::TechnicalCommittee(_) + RuntimeCall::TechnicalCommittee(_) | + RuntimeCall::DeveloperCommittee(_) ) { // always allow core calls return true @@ -1325,6 +1351,7 @@ impl Contains for NormalModeFilter { // memberships RuntimeCall::CouncilMembership(_) | RuntimeCall::TechnicalCommitteeMembership(_) | + RuntimeCall::DeveloperCommitteeMembership(_) | // democracy, we don't subdivide the calls, so we allow public proposals RuntimeCall::Democracy(_) | // Preimage @@ -1364,7 +1391,8 @@ impl Contains for NormalModeFilter { RuntimeCall::AccountFix(_) | RuntimeCall::Bitacross(_) | RuntimeCall::BitacrossMimic(_) | - RuntimeCall::EvmAssertions(_) + RuntimeCall::EvmAssertions(_) | + RuntimeCall::ScoreStaking(_) ) } } diff --git a/scripts/generate-release-notes.sh b/scripts/generate-release-notes.sh index f516e9ce9d..c95eb595e3 100755 --- a/scripts/generate-release-notes.sh +++ b/scripts/generate-release-notes.sh @@ -202,7 +202,7 @@ mrenclave: : $MRENCLAVE EOF fi -if is_identity_worker_release; then +if is_bitacross_worker_release; then WORKER_VERSION=$(grep version bitacross-worker/service/Cargo.toml | head -n1 | sed "s/'$//;s/.*'//") WORKER_BIN=$(grep name bitacross-worker/service/Cargo.toml | head -n1 | sed "s/'$//;s/.*'//") WORKER_RUSTC_VERSION=$(cd bitacross-worker && rustc --version) diff --git a/scripts/pre-commit.sh b/scripts/pre-commit.sh index 37b3cb31ff..facd7f0b25 100755 --- a/scripts/pre-commit.sh +++ b/scripts/pre-commit.sh @@ -36,6 +36,10 @@ function clean_up() { cargo clean cd "$root_dir/tee-worker/enclave-runtime" cargo clean + cd "$root_dir/bitacross-worker" + cargo clean + cd "$root_dir/bitacross-worker/enclave-runtime" + cargo clean } root_dir=$(git rev-parse --show-toplevel) diff --git a/tee-worker/Cargo.lock b/tee-worker/Cargo.lock index ac02b6f6ff..05c62a3cd4 100644 --- a/tee-worker/Cargo.lock +++ b/tee-worker/Cargo.lock @@ -712,18 +712,17 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits 0.2.16", "serde 1.0.193", - "time", "wasm-bindgen", - "winapi 0.3.9", + "windows-targets 0.52.5", ] [[package]] @@ -2963,7 +2962,7 @@ dependencies = [ "itp-utils", "lc-dynamic-assertion", "lc-evm-dynamic-assertions", - "lc-scheduled-enclave", + "lc-vc-task-sender", "litentry-hex-utils", "litentry-primitives", "log 0.4.20", @@ -3175,7 +3174,6 @@ dependencies = [ "itp-types", "itp-utils", "lc-evm-dynamic-assertions", - "lc-scheduled-enclave", "litentry-primitives", "log 0.4.20", "parity-scale-codec", @@ -3306,7 +3304,7 @@ name = "itc-tls-websocket-server" version = "0.9.0" dependencies = [ "bit-vec", - "chrono 0.4.26", + "chrono 0.4.38", "env_logger 0.9.3", "log 0.4.20", "mio 0.6.21", @@ -3391,7 +3389,7 @@ dependencies = [ "base64 0.13.1", "bit-vec", "chrono 0.4.11", - "chrono 0.4.26", + "chrono 0.4.38", "hex", "httparse 1.4.1", "itertools 0.10.5", @@ -3827,7 +3825,7 @@ name = "itp-time-utils" version = "0.9.0" dependencies = [ "chrono 0.4.11", - "chrono 0.4.26", + "chrono 0.4.38", "sgx_tstd", ] @@ -3990,7 +3988,6 @@ dependencies = [ "its-state", "its-test", "its-validateer-fetch", - "lc-scheduled-enclave", "litentry-hex-utils", "log 0.4.20", "parity-scale-codec", @@ -4055,7 +4052,6 @@ dependencies = [ "its-state", "its-test", "lazy_static", - "lc-scheduled-enclave", "log 0.4.20", "parity-scale-codec", "sgx_tstd", @@ -4536,7 +4532,7 @@ name = "lc-credentials" version = "0.1.0" dependencies = [ "chrono 0.4.11", - "chrono 0.4.26", + "chrono 0.4.38", "hex", "itp-stf-primitives", "itp-time-utils", @@ -4585,7 +4581,7 @@ version = "0.1.0" dependencies = [ "base64 0.22.0", "chrono 0.4.11", - "chrono 0.4.26", + "chrono 0.4.38", "env_logger 0.10.0", "hex", "http 0.2.1", @@ -4624,6 +4620,8 @@ version = "0.1.0" dependencies = [ "base58", "blake2-rfc", + "chrono 0.4.11", + "chrono 0.4.38", "ethabi", "evm 0.41.1", "hex", @@ -4717,22 +4715,6 @@ dependencies = [ "sp-runtime", ] -[[package]] -name = "lc-scheduled-enclave" -version = "0.8.0" -dependencies = [ - "itp-settings", - "itp-sgx-io", - "itp-types", - "lazy_static", - "log 0.4.20", - "parity-scale-codec", - "sgx_tstd", - "sp-std 5.0.0", - "thiserror 1.0.44", - "thiserror 1.0.9", -] - [[package]] name = "lc-service" version = "0.1.0" @@ -5023,7 +5005,7 @@ version = "0.0.1" dependencies = [ "array-bytes 6.1.0", "base58", - "chrono 0.4.26", + "chrono 0.4.38", "clap 4.1.0", "env_logger 0.9.3", "frame-metadata", @@ -6168,7 +6150,7 @@ name = "pallet-teebag" version = "0.1.0" dependencies = [ "base64 0.13.1", - "chrono 0.4.26", + "chrono 0.4.38", "der 0.6.1", "frame-support", "frame-system", @@ -6882,7 +6864,7 @@ version = "0.9.2" source = "git+https://github.com/integritee-network/rcgen#1852c8dbeb74de36a422d218254b659497daf717" dependencies = [ "chrono 0.4.11", - "chrono 0.4.26", + "chrono 0.4.38", "pem 0.8.2", "pem 1.1.1", "ring 0.16.19", @@ -9043,17 +9025,6 @@ dependencies = [ "once_cell 1.18.0", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi 0.3.9", -] - [[package]] name = "tiny-bip39" version = "1.0.0" @@ -9323,7 +9294,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" dependencies = [ "ansi_term", - "chrono 0.4.26", + "chrono 0.4.38", "lazy_static", "matchers", "regex 1.9.5", @@ -9727,12 +9698,6 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -10162,6 +10127,22 @@ dependencies = [ "windows_x86_64_msvc 0.48.0", ] +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -10174,6 +10155,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -10186,6 +10173,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -10198,6 +10191,18 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -10210,6 +10215,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -10222,6 +10233,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -10234,6 +10251,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -10246,6 +10269,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + [[package]] name = "winnow" version = "0.5.1" @@ -10402,7 +10431,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e262a29d0e61ccf2b6190d7050d4b237535fc76ce4c1210d9caa316f71dffa75" dependencies = [ "bit-vec", - "chrono 0.4.26", + "chrono 0.4.38", "num-bigint 0.4.3", ] diff --git a/tee-worker/Makefile b/tee-worker/Makefile index 048d62e241..d937bd0b2b 100755 --- a/tee-worker/Makefile +++ b/tee-worker/Makefile @@ -30,6 +30,7 @@ SGX_PRODUCTION ?= 0 WORKER_MODE ?= sidechain WORKER_DEV ?= 0 WORKER_MOCK_SERVER ?= 0 +RA_METHOD ?= SKIP_WASM_BUILD = 1 # include the build settings from rust-sgx-sdk @@ -87,16 +88,16 @@ ifeq ($(SGX_PRODUCTION), 1) SGX_ENCLAVE_CONFIG = "enclave-runtime/Enclave.config.production.xml" SGX_SIGN_KEY = $(SGX_COMMERCIAL_KEY) SGX_SIGN_PASSFILE = $(SGX_PASSFILE) - WORKER_FEATURES := --features=link-binary,$(WORKER_MODE),$(WORKER_FEATURES),$(ADDITIONAL_FEATURES) + WORKER_FEATURES := --features=link-binary,$(WORKER_MODE),$(RA_METHOD),$(WORKER_FEATURES),$(ADDITIONAL_FEATURES) else SGX_ENCLAVE_MODE = "Development Mode" SGX_ENCLAVE_CONFIG = "enclave-runtime/Enclave.config.xml" SGX_SIGN_KEY = "enclave-runtime/Enclave_private.pem" SGX_SIGN_PASSFILE = "" - WORKER_FEATURES := --features=default,link-binary,$(WORKER_MODE),$(WORKER_FEATURES),$(ADDITIONAL_FEATURES) + WORKER_FEATURES := --features=default,link-binary,$(WORKER_MODE),$(RA_METHOD),$(WORKER_FEATURES),$(ADDITIONAL_FEATURES) endif -CLIENT_FEATURES = --features=$(WORKER_MODE),$(ADDITIONAL_FEATURES) +CLIENT_FEATURES = --features=$(WORKER_MODE),$(RA_METHOD),$(ADDITIONAL_FEATURES) # check if running on Jenkins ifdef BUILD_ID diff --git a/tee-worker/app-libs/parentchain-interface/Cargo.toml b/tee-worker/app-libs/parentchain-interface/Cargo.toml index 9a06c023fb..a3bf24e150 100644 --- a/tee-worker/app-libs/parentchain-interface/Cargo.toml +++ b/tee-worker/app-libs/parentchain-interface/Cargo.toml @@ -34,7 +34,7 @@ sp-runtime = { default-features = false, git = "https://github.com/paritytech/su # litentry lc-dynamic-assertion = { path = "../../litentry/core/dynamic-assertion", default-features = false } lc-evm-dynamic-assertions = { path = "../../litentry/core/evm-dynamic-assertions", default-features = false } -lc-scheduled-enclave = { path = "../../litentry/core/scheduled-enclave", default-features = false, optional = true } +lc-vc-task-sender = { path = "../../litentry/core/vc-task/sender", default-features = false } litentry-hex-utils = { path = "../../../primitives/hex", default-features = false } litentry-primitives = { path = "../../litentry/primitives", default-features = false } @@ -73,9 +73,9 @@ std = [ "sp-runtime/std", "substrate-api-client", "litentry-primitives/std", - "lc-scheduled-enclave/std", "lc-dynamic-assertion/std", "lc-evm-dynamic-assertions/std", + "lc-vc-task-sender/std", "sp-std/std", ] sgx = [ @@ -87,7 +87,7 @@ sgx = [ "itp-stf-executor/sgx", "itp-top-pool-author/sgx", "litentry-primitives/sgx", - "lc-scheduled-enclave/sgx", "lc-dynamic-assertion/sgx", "lc-evm-dynamic-assertions/sgx", + "lc-vc-task-sender/sgx", ] diff --git a/tee-worker/app-libs/parentchain-interface/src/integritee/event_filter.rs b/tee-worker/app-libs/parentchain-interface/src/integritee/event_filter.rs index 1fbdb5e9e2..456cebe639 100644 --- a/tee-worker/app-libs/parentchain-interface/src/integritee/event_filter.rs +++ b/tee-worker/app-libs/parentchain-interface/src/integritee/event_filter.rs @@ -24,8 +24,8 @@ use itp_types::{ parentchain::{ events::{ ActivateIdentityRequested, AssertionCreated, DeactivateIdentityRequested, - LinkIdentityRequested, OpaqueTaskPosted, ParentchainBlockProcessed, - ScheduledEnclaveRemoved, ScheduledEnclaveSet, VCRequested, + EnclaveUnauthorized, LinkIdentityRequested, OpaqueTaskPosted, + ParentchainBlockProcessed, VCRequested, }, FilterEvents, }, @@ -87,13 +87,7 @@ impl FilterEvents for FilterableEvents { self.filter() } - fn get_scheduled_enclave_set_events(&self) -> Result, Self::Error> { - self.filter() - } - - fn get_scheduled_enclave_removed_events( - &self, - ) -> Result, Self::Error> { + fn get_enclave_unauthorized_events(&self) -> Result, Self::Error> { self.filter() } diff --git a/tee-worker/app-libs/parentchain-interface/src/integritee/event_handler.rs b/tee-worker/app-libs/parentchain-interface/src/integritee/event_handler.rs index 7e45d38392..5a11d596c5 100644 --- a/tee-worker/app-libs/parentchain-interface/src/integritee/event_handler.rs +++ b/tee-worker/app-libs/parentchain-interface/src/integritee/event_handler.rs @@ -24,17 +24,13 @@ use itp_stf_primitives::{traits::IndirectExecutor, types::TrustedOperation}; use itp_types::{ parentchain::{ events::ParentchainBlockProcessed, AccountId, FilterEvents, HandleParentchainEvents, - ParentchainEventProcessingError, + ParentchainEventProcessingError, ProcessedEventsArtifacts, }, RsaRequest, H256, }; -use lc_scheduled_enclave::{ScheduledEnclaveUpdater, GLOBAL_SCHEDULED_ENCLAVE}; - use lc_dynamic_assertion::AssertionLogicRepository; use lc_evm_dynamic_assertions::repository::EvmAssertionRepository; -use litentry_primitives::{ - Assertion, Identity, MrEnclave, SidechainBlockNumber, ValidationData, Web3Network, WorkerType, -}; +use litentry_primitives::{Assertion, Identity, ValidationData, Web3Network}; use log::*; use sp_core::{blake2_256, H160}; use sp_std::vec::Vec; @@ -163,33 +159,6 @@ impl ParentchainEventHandler { Ok(()) } - fn set_scheduled_enclave( - worker_type: WorkerType, - sbn: SidechainBlockNumber, - mrenclave: MrEnclave, - ) -> Result<(), Error> { - if worker_type != WorkerType::Identity { - warn!("Ignore SetScheduledEnclave due to wrong worker_type"); - return Ok(()) - } - GLOBAL_SCHEDULED_ENCLAVE.update(sbn, mrenclave)?; - - Ok(()) - } - - fn remove_scheduled_enclave( - worker_type: WorkerType, - sbn: SidechainBlockNumber, - ) -> Result<(), Error> { - if worker_type != WorkerType::Identity { - warn!("Ignore RemoveScheduledEnclave due to wrong worker_type"); - return Ok(()) - } - GLOBAL_SCHEDULED_ENCLAVE.remove(sbn)?; - - Ok(()) - } - fn post_opaque_task>( executor: &Executor, request: &RsaRequest, @@ -243,8 +212,10 @@ where &self, executor: &Executor, events: impl FilterEvents, - ) -> Result, Error> { + ) -> Result { let mut handled_events: Vec = Vec::new(); + let mut successful_assertion_ids: Vec = Vec::new(); + let mut failed_assertion_ids: Vec = Vec::new(); if let Ok(events) = events.get_link_identity_events() { debug!("Handling link_identity events"); events @@ -316,41 +287,6 @@ where .map_err(|_| ParentchainEventProcessingError::VCRequestedFailure)?; } - if let Ok(events) = events.get_scheduled_enclave_set_events() { - debug!("Handling ScheduledEnclaveSet events"); - events - .iter() - .try_for_each(|event| { - debug!("found ScheduledEnclaveSet event: {:?}", event); - let result = Self::set_scheduled_enclave( - event.worker_type, - event.sidechain_block_number, - event.mrenclave, - ); - handled_events.push(hash_of(&event)); - - result - }) - .map_err(|_| ParentchainEventProcessingError::ScheduledEnclaveSetFailure)?; - } - - if let Ok(events) = events.get_scheduled_enclave_removed_events() { - debug!("Handling ScheduledEnclaveRemoved events"); - events - .iter() - .try_for_each(|event| { - debug!("found ScheduledEnclaveRemoved event: {:?}", event); - let result = Self::remove_scheduled_enclave( - event.worker_type, - event.sidechain_block_number, - ); - handled_events.push(hash_of(&event)); - - result - }) - .map_err(|_| ParentchainEventProcessingError::ScheduledEnclaveRemovedFailure)?; - } - if let Ok(events) = events.get_opaque_task_posted_events() { debug!("Handling OpaqueTaskPosted events"); events @@ -375,6 +311,11 @@ where let result = self.store_assertion(executor, event.id, event.byte_code, event.secrets); handled_events.push(event_hash); + if result.is_ok() { + successful_assertion_ids.push(event.id); + } else { + failed_assertion_ids.push(event.id) + } result }) .map_err(|_| ParentchainEventProcessingError::AssertionCreatedFailure)?; @@ -389,7 +330,7 @@ where }); } - Ok(handled_events) + Ok((handled_events, successful_assertion_ids, failed_assertion_ids)) } } diff --git a/tee-worker/app-libs/parentchain-interface/src/target_a/event_filter.rs b/tee-worker/app-libs/parentchain-interface/src/target_a/event_filter.rs index 8de5b0e7f1..2490b2e1d9 100644 --- a/tee-worker/app-libs/parentchain-interface/src/target_a/event_filter.rs +++ b/tee-worker/app-libs/parentchain-interface/src/target_a/event_filter.rs @@ -84,15 +84,9 @@ impl FilterEvents for FilterableEvents { self.filter() } - fn get_scheduled_enclave_set_events( + fn get_enclave_unauthorized_events( &self, - ) -> Result, Self::Error> { - self.filter() - } - - fn get_scheduled_enclave_removed_events( - &self, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { self.filter() } diff --git a/tee-worker/app-libs/parentchain-interface/src/target_a/event_handler.rs b/tee-worker/app-libs/parentchain-interface/src/target_a/event_handler.rs index cc563e2147..af091e98f8 100644 --- a/tee-worker/app-libs/parentchain-interface/src/target_a/event_handler.rs +++ b/tee-worker/app-libs/parentchain-interface/src/target_a/event_handler.rs @@ -20,9 +20,8 @@ pub use ita_sgx_runtime::{Balance, Index}; use ita_stf::TrustedCallSigned; use itc_parentchain_indirect_calls_executor::error::Error; use itp_stf_primitives::traits::IndirectExecutor; -use itp_types::parentchain::{FilterEvents, HandleParentchainEvents}; +use itp_types::parentchain::{FilterEvents, HandleParentchainEvents, ProcessedEventsArtifacts}; use log::*; -use sp_core::H256; use sp_std::vec::Vec; pub struct ParentchainEventHandler {} @@ -36,8 +35,8 @@ where &self, _executor: &Executor, _events: impl FilterEvents, - ) -> Result, Error> { + ) -> Result { debug!("not handling any events for target a"); - Ok(Vec::new()) + Ok((Vec::new(), Vec::new(), Vec::new())) } } diff --git a/tee-worker/app-libs/parentchain-interface/src/target_b/event_filter.rs b/tee-worker/app-libs/parentchain-interface/src/target_b/event_filter.rs index 8de5b0e7f1..2490b2e1d9 100644 --- a/tee-worker/app-libs/parentchain-interface/src/target_b/event_filter.rs +++ b/tee-worker/app-libs/parentchain-interface/src/target_b/event_filter.rs @@ -84,15 +84,9 @@ impl FilterEvents for FilterableEvents { self.filter() } - fn get_scheduled_enclave_set_events( + fn get_enclave_unauthorized_events( &self, - ) -> Result, Self::Error> { - self.filter() - } - - fn get_scheduled_enclave_removed_events( - &self, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { self.filter() } diff --git a/tee-worker/app-libs/parentchain-interface/src/target_b/event_handler.rs b/tee-worker/app-libs/parentchain-interface/src/target_b/event_handler.rs index 4bf433f7f2..56151a9ccc 100644 --- a/tee-worker/app-libs/parentchain-interface/src/target_b/event_handler.rs +++ b/tee-worker/app-libs/parentchain-interface/src/target_b/event_handler.rs @@ -20,9 +20,8 @@ pub use ita_sgx_runtime::{Balance, Index}; use ita_stf::TrustedCallSigned; use itc_parentchain_indirect_calls_executor::error::Error; use itp_stf_primitives::traits::IndirectExecutor; -use itp_types::parentchain::{FilterEvents, HandleParentchainEvents}; +use itp_types::parentchain::{FilterEvents, HandleParentchainEvents, ProcessedEventsArtifacts}; use log::*; -use sp_core::H256; use sp_std::vec::Vec; pub struct ParentchainEventHandler {} @@ -36,8 +35,8 @@ where &self, _executor: &Executor, _events: impl FilterEvents, - ) -> Result, Error> { + ) -> Result { debug!("not handling any events for target B"); - Ok(Vec::new()) + Ok((Vec::new(), Vec::new(), Vec::new())) } } diff --git a/tee-worker/app-libs/sgx-runtime/src/lib.rs b/tee-worker/app-libs/sgx-runtime/src/lib.rs index b476d07b6b..344e9cd258 100644 --- a/tee-worker/app-libs/sgx-runtime/src/lib.rs +++ b/tee-worker/app-libs/sgx-runtime/src/lib.rs @@ -139,7 +139,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node-template"), impl_name: create_runtime_str!("node-template"), authoring_version: 1, - spec_version: 108, + spec_version: 109, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/tee-worker/app-libs/stf/src/helpers.rs b/tee-worker/app-libs/stf/src/helpers.rs index 4842f066e7..b0f75e4eb8 100644 --- a/tee-worker/app-libs/stf/src/helpers.rs +++ b/tee-worker/app-libs/stf/src/helpers.rs @@ -14,6 +14,7 @@ limitations under the License. */ + use crate::{Vec, ENCLAVE_ACCOUNT_KEY}; use codec::{Decode, Encode}; use frame_support::ensure; @@ -23,6 +24,7 @@ use itp_stf_primitives::error::{StfError, StfResult}; use itp_storage::{storage_double_map_key, storage_map_key, storage_value_key, StorageHasher}; use itp_types::Index; use itp_utils::stringify::account_id_to_string; +use litentry_hex_utils::hex_encode; use litentry_primitives::{ErrorDetail, Identity, Web3ValidationData}; use log::*; use sp_core::blake2_256; @@ -145,18 +147,34 @@ pub fn get_expected_raw_message( blake2_256(payload.as_slice()).to_vec() } +// [P-923] Verify a web3 identity +// This function validates the signature with both the raw message and its prettified format. Any of them is valid. +// The prettified version was introduced to extend the support for utf-8 signatures for browser wallets that +// do not play well with raw bytes signing, like Solana's Phantom and OKX wallets. +// +// The prettified format is the raw message with a prefix "Token: ". pub fn verify_web3_identity( identity: &Identity, - raw_msg: &[u8], - data: &Web3ValidationData, + expected_raw_msg: &[u8], + validation_data: &Web3ValidationData, ) -> StfResult<()> { + let mut expected_prettified_msg = hex_encode(expected_raw_msg); + expected_prettified_msg.insert_str(0, "Token: "); + + let expected_prettified_msg = expected_prettified_msg.as_bytes(); + + let received_message = validation_data.message().as_slice(); + ensure!( - raw_msg == data.message().as_slice(), + expected_raw_msg == received_message || expected_prettified_msg == received_message, StfError::LinkIdentityFailed(ErrorDetail::UnexpectedMessage) ); + let signature = validation_data.signature(); + ensure!( - data.signature().verify(raw_msg, identity), + signature.verify(expected_raw_msg, identity) + || signature.verify(expected_prettified_msg, identity), StfError::LinkIdentityFailed(ErrorDetail::VerifyWeb3SignatureFailed) ); diff --git a/tee-worker/app-libs/stf/src/trusted_call.rs b/tee-worker/app-libs/stf/src/trusted_call.rs index 24fb83ff25..3f0277f54b 100644 --- a/tee-worker/app-libs/stf/src/trusted_call.rs +++ b/tee-worker/app-libs/stf/src/trusted_call.rs @@ -876,6 +876,7 @@ where if let Some(key) = maybe_key { Ok(TrustedCallResult::RequestVC(RequestVCResult { vc_payload: aes_encrypt_default(&key, &vc_payload), + vc_logs: None, pre_mutated_id_graph: aes_encrypt_default(&key, &mutated_id_graph.encode()), pre_id_graph_hash: id_graph_hash, })) diff --git a/tee-worker/app-libs/stf/src/trusted_call_litentry.rs b/tee-worker/app-libs/stf/src/trusted_call_litentry.rs index dc53e6a9ab..5e287f8eca 100644 --- a/tee-worker/app-libs/stf/src/trusted_call_litentry.rs +++ b/tee-worker/app-libs/stf/src/trusted_call_litentry.rs @@ -103,12 +103,14 @@ impl TrustedCallSigned { .map_err(|_| StfError::LinkIdentityFailed(ErrorDetail::SendStfRequestFailed))?; Ok(false) }, - ValidationData::Web3(data) => { + ValidationData::Web3(validation_data) => { ensure!( identity.is_web3(), StfError::LinkIdentityFailed(ErrorDetail::InvalidIdentity) ); - verify_web3_identity(&identity, &raw_msg, &data)?; + + verify_web3_identity(&identity, &raw_msg, &validation_data)?; + Ok(true) }, } diff --git a/tee-worker/app-libs/stf/src/trusted_call_result.rs b/tee-worker/app-libs/stf/src/trusted_call_result.rs index d8b11c7449..c70a2cccb8 100644 --- a/tee-worker/app-libs/stf/src/trusted_call_result.rs +++ b/tee-worker/app-libs/stf/src/trusted_call_result.rs @@ -97,6 +97,8 @@ pub struct SetIdentityNetworksResult { #[derive(Encode, Decode, Clone, Debug, PartialEq, Eq)] pub struct RequestVCResult { pub vc_payload: AesOutput, + // Mainly used to returning logs in dynamic contract VC. + pub vc_logs: Option, // see comments in `lc-vc-task-receiver` why it's prefixed with `pre...` // they should be referenced/used only when the client's local IDGraph is empty pub pre_mutated_id_graph: AesOutput, diff --git a/tee-worker/build.Dockerfile b/tee-worker/build.Dockerfile index 0715ef636e..e36071a5aa 100644 --- a/tee-worker/build.Dockerfile +++ b/tee-worker/build.Dockerfile @@ -152,6 +152,11 @@ ARG UID=1000 RUN adduser -u ${UID} --disabled-password --gecos '' litentry RUN adduser -u ${UID} litentry sudo RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers +# to fix Multi-node distributed worker encounters SGX permission errors. +RUN groupadd -g 121 sgx_prv && \ + groupadd -g 108 sgx && \ + usermod -aG sgx litentry && \ + usermod -aG sgx_prv litentry COPY --from=local-builder:latest /opt/sgxsdk /opt/sgxsdk COPY --from=local-builder:latest /lib/x86_64-linux-gnu/libsgx* /lib/x86_64-linux-gnu/ diff --git a/tee-worker/cli/lit_test_dr_vc.sh b/tee-worker/cli/lit_test_dr_vc.sh index bcabc56b55..1d8fd4d3f0 100755 --- a/tee-worker/cli/lit_test_dr_vc.sh +++ b/tee-worker/cli/lit_test_dr_vc.sh @@ -195,6 +195,8 @@ assertion_vec=( "platform-user karat-dao-user" "nft-holder weirdo-ghost-gang" "nft-holder club3-sbt" + "nft-holder mfan" + "nft-holder mvp" ) assertions=() diff --git a/tee-worker/cli/lit_ts_integration_test.sh b/tee-worker/cli/lit_ts_integration_test.sh index a97d902bbc..f984b186b2 100755 --- a/tee-worker/cli/lit_ts_integration_test.sh +++ b/tee-worker/cli/lit_ts_integration_test.sh @@ -62,10 +62,29 @@ cd /client-api/sidechain-api ${CLIENT} print-sgx-metadata-raw > prepare-build/litentry-sidechain-metadata.json echo "update sidechain metadata" + cd /client-api pnpm install pnpm run build -cd /ts-tests -pnpm install +if [ "$TEST" = "assertion_contracts.test.ts" ]; then + cd / + ls assertion-contracts/ + cp -r assertion-contracts /ts-tests/integration-tests/contracts + + cd /ts-tests + curl -L https://foundry.paradigm.xyz | bash + source /root/.bashrc + apt install -y git + foundryup + + pnpm install + pnpm --filter integration-tests run compile-contracts + +else + cd /ts-tests + pnpm install + +fi + NODE_ENV=staging pnpm --filter integration-tests run test $TEST diff --git a/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc.rs b/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc.rs index 3985c22197..3c1fa77572 100644 --- a/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc.rs +++ b/tee-worker/cli/src/trusted_base_cli/commands/litentry/request_vc.rs @@ -30,12 +30,12 @@ use litentry_primitives::{ aes_decrypt, AchainableAmount, AchainableAmountHolding, AchainableAmountToken, AchainableAmounts, AchainableBasic, AchainableBetweenPercents, AchainableClassOfYear, AchainableDate, AchainableDateInterval, AchainableDatePercent, AchainableParams, - AchainableToken, Assertion, BnbDigitDomainType, BoundedWeb3Network, ContestType, DynamicParams, - EVMTokenType, GenericDiscordRoleType, Identity, OneBlockCourseType, ParameterString, - PlatformUserType, RequestAesKey, SoraQuizType, VIP3MembershipCardLevel, Web3Network, - Web3NftType, Web3TokenType, REQUEST_AES_KEY_LEN, + AchainableToken, Assertion, BnbDigitDomainType, BoundedWeb3Network, ContestType, + DynamicContractParams, DynamicParams, EVMTokenType, GenericDiscordRoleType, Identity, + OneBlockCourseType, ParameterString, PlatformUserType, RequestAesKey, SoraQuizType, + VIP3MembershipCardLevel, Web3Network, Web3NftType, Web3TokenType, REQUEST_AES_KEY_LEN, }; -use sp_core::{Pair, H160}; +use sp_core::{Pair, H160, H256}; // usage example below // @@ -160,7 +160,8 @@ pub struct DynamicArg { pub smart_contract_id: String, // hex encoded smart contract params // can use this online tool to encode params: https://abi.hashex.org/ - pub smart_contract_param: String, + pub smart_contract_param: Option, + pub return_log: Option, } #[derive(Args, Debug)] @@ -277,18 +278,23 @@ pub enum TokenHoldingAmountCommand { Mcrt, Btc, Bean, + An, + Tuna, } #[derive(Subcommand, Debug)] pub enum PlatformUserCommand { - KaratDaoUser, - MagicCraftStakingUser, + KaratDao, + MagicCraftStaking, + DarenMarket, } #[derive(Subcommand, Debug)] pub enum NftHolderCommand { WeirdoGhostGang, Club3Sbt, + MFan, + Mvp, } // positional args (to vec) + required arg + optional arg is a nightmare combination for clap parser, @@ -362,6 +368,21 @@ AchainableCommandArgs!(TokenArg, { token: String, }); +fn print_vc(key: &RequestAesKey, mut vc: RequestVCResult) { + let decrypted = aes_decrypt(key, &mut vc.vc_payload).unwrap(); + let credential_str = String::from_utf8(decrypted).expect("Found invalid UTF-8"); + println!("----Generated VC-----"); + println!("{}", credential_str); + if let Some(mut vc_logs) = vc.vc_logs { + let decrypted_logs = aes_decrypt(key, &mut vc_logs).unwrap(); + if !decrypted_logs.is_empty() { + let logs_str = String::from_utf8(decrypted_logs).expect("Found invalid UTF-8"); + println!("----VC Logging-----"); + println!("{}", logs_str); + } + } +} + impl RequestVcCommand { pub(crate) fn run(&self, cli: &Cli, trusted_cli: &TrustedCli) -> CliResult { let alice = get_pair_from_str(trusted_cli, "//Alice", cli); @@ -397,19 +418,28 @@ impl RequestVcCommand { ) .sign(&KeyPair::Sr25519(Box::new(alice.clone())), nonce, &mrenclave, &shard) .into_trusted_operation(trusted_cli.direct); + + if trusted_cli.direct { match perform_trusted_operation::(cli, trusted_cli, &top) { - Ok(mut vc) => { - let decrypted = aes_decrypt(&key, &mut vc.vc_payload).unwrap(); - let credential_str = - String::from_utf8(decrypted).expect("Found invalid UTF-8"); - println!("----Generated VC-----"); - println!("{}", credential_str); + Ok(vc) => { + print_vc(&key, vc); }, Err(e) => { println!("{:?}", e); }, } - nonce += 1; + } else { + println!("WARNING: This method does not support printing VC, Please use -d for direct invocation to print the VC"); + match perform_trusted_operation::(cli, trusted_cli, &top) { + Ok(block_hash) => { + println!("Request VC Event included in block hash: {:?}", block_hash) + }, + Err(e) => { + println!("{:?}", e); + }, + } + } + nonce += 1; }); } else { let top = TrustedCall::request_batch_vc( @@ -430,13 +460,8 @@ impl RequestVcCommand { println!("received one error: {:?}", err); }, Ok(payload) => { - let mut vc = - RequestVCResult::decode(&mut payload.as_slice()).unwrap(); - let decrypted = aes_decrypt(&key, &mut vc.vc_payload).unwrap(); - let credential_str = - String::from_utf8(decrypted).expect("Found invalid UTF-8"); - println!("----Generated VC-----"); - println!("{}", credential_str); + let vc = RequestVCResult::decode(&mut payload.as_slice()).unwrap(); + print_vc(&key, vc); }, } }, @@ -624,37 +649,54 @@ impl Command { TokenHoldingAmountCommand::Mcrt => TokenHoldingAmount(Web3TokenType::Mcrt), TokenHoldingAmountCommand::Btc => TokenHoldingAmount(Web3TokenType::Btc), TokenHoldingAmountCommand::Bean => TokenHoldingAmount(Web3TokenType::Bean), + TokenHoldingAmountCommand::An => TokenHoldingAmount(Web3TokenType::An), + TokenHoldingAmountCommand::Tuna => TokenHoldingAmount(Web3TokenType::Tuna), }), Command::PlatformUser(arg) => Ok(match arg { - PlatformUserCommand::KaratDaoUser => PlatformUser(PlatformUserType::KaratDaoUser), - PlatformUserCommand::MagicCraftStakingUser => - PlatformUser(PlatformUserType::MagicCraftStakingUser), + PlatformUserCommand::KaratDao => PlatformUser(PlatformUserType::KaratDao), + PlatformUserCommand::MagicCraftStaking => + PlatformUser(PlatformUserType::MagicCraftStaking), + PlatformUserCommand::DarenMarket => PlatformUser(PlatformUserType::DarenMarket), }), Command::NftHolder(arg) => Ok(match arg { NftHolderCommand::WeirdoGhostGang => NftHolder(Web3NftType::WeirdoGhostGang), NftHolderCommand::Club3Sbt => NftHolder(Web3NftType::Club3Sbt), + NftHolderCommand::MFan => NftHolder(Web3NftType::MFan), + NftHolderCommand::Mvp => NftHolder(Web3NftType::Mvp), }), Command::Dynamic(arg) => { let decoded_id = hex::decode(&arg.smart_contract_id.clone()).unwrap(); let id_bytes: [u8; 20] = decoded_id.try_into().unwrap(); - let params = hex::decode(&arg.smart_contract_param.clone()).unwrap(); - let params_len = params.len(); - let truncated_params = DynamicParams::truncate_from(params); - let truncated_params_len = truncated_params.len(); - if params_len > truncated_params_len { - println!( - "The dynamic params length {} is over the maximum value {}", - params_len, truncated_params_len - ); - Err(CliError::Extrinsic { - msg: format!( - "The dynamic params length {} is over the maximum value {}", - params_len, truncated_params_len - ), - }) - } else { - Ok(Assertion::Dynamic(H160::from(id_bytes), truncated_params)) - } + + let smart_contract_params = match &arg.smart_contract_param { + Some(p) => { + let params = hex::decode(p).unwrap(); + let params_len = params.len(); + let truncated_params = DynamicContractParams::truncate_from(params); + let truncated_params_len = truncated_params.len(); + if params_len > truncated_params_len { + println!( + "The dynamic params length {} is over the maximum value {}", + params_len, truncated_params_len + ); + Err(CliError::Extrinsic { + msg: format!( + "The dynamic params length {} is over the maximum value {}", + params_len, truncated_params_len + ), + }) + } else { + Ok(Some(truncated_params)) + } + }, + None => Ok(None), + }?; + + Ok(Assertion::Dynamic(DynamicParams { + smart_contract_id: H160::from(id_bytes), + smart_contract_params, + return_log: arg.return_log.unwrap_or_default(), + })) }, } } diff --git a/tee-worker/client-api/parachain-api/CHANGELOG.md b/tee-worker/client-api/parachain-api/CHANGELOG.md new file mode 100644 index 0000000000..d7eba1f302 --- /dev/null +++ b/tee-worker/client-api/parachain-api/CHANGELOG.md @@ -0,0 +1,49 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- (#2930) `PlatformUserType`: Add `DarenMarket` + +### Changed + +- (#2930) `PlatformUserType`: rename `MagicCraftStakingUser` to `MagicCraftStaking` +- (#2930) `PlatformUserType`: rename `KaratDaoUser` to `KaratDao` + +## [0.9.18-10] - 2024-07-15 + +Matching version for [parachain-release v0.9.18-10](https://github.com/litentry/litentry-parachain/releases/tag/v0.9.18-10) + +## [0.9.18-next.11] - 2024-07-12 + +### Added + +- (#2877, #2889) Add `MFan` and `Mvp` to `Web3NftType` +- (#2884) Add `An` and `Tuna` to the list of `Web3TokenType` + +## [0.9.18-next.8] - 2024-07-02 + +Routinely update + +## [0.9.18-next.7] - 2024-06-19 + +### Added + +- `Web3Network`: add `Combo`. +- Add `SubstrateNetwork`, `EvmNetwork`, `SolanaNetwork`, `BitcoinNetwork`, `Web2Network`, `PrimeIdentity` types. + +## [0.9.18-next.6] - 2024-06-12 + +### Changed + +- `package.json`: add `module` entry and mark it as side-effects free. + +## [0.9.18-next.5] - 2024-06-12 + +- Routinary update diff --git a/tee-worker/client-api/parachain-api/README.md b/tee-worker/client-api/parachain-api/README.md index 5b9afe455a..e301ec6e1d 100644 --- a/tee-worker/client-api/parachain-api/README.md +++ b/tee-worker/client-api/parachain-api/README.md @@ -45,6 +45,8 @@ Versions in the pattern of `x.x.x-next.x` feature the most recent code version t 1. [Update your published package version number](https://docs.npmjs.com/updating-your-published-package-version-number) +1. Update the `CHANGELOG.md` file + 1. Build the package ```s diff --git a/tee-worker/client-api/parachain-api/package.json b/tee-worker/client-api/parachain-api/package.json index b227c1e61e..8c41438241 100644 --- a/tee-worker/client-api/parachain-api/package.json +++ b/tee-worker/client-api/parachain-api/package.json @@ -3,7 +3,9 @@ "type": "module", "license": "ISC", "main": "dist/src/index.js", - "version": "0.9.17-1", + "module": "dist/src/index.js", + "sideEffects": false, + "version": "0.9.18-10-next.0", "scripts": { "clean": "rm -rf dist build node_modules", "update-metadata": "curl -s -H \"Content-Type: application/json\" -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9944 > prepare-build/litentry-parachain-metadata.json", diff --git a/tee-worker/client-api/parachain-api/prepare-build/interfaces/identity/definitions.ts b/tee-worker/client-api/parachain-api/prepare-build/interfaces/identity/definitions.ts index f7a6f38284..767dfe265a 100644 --- a/tee-worker/client-api/parachain-api/prepare-build/interfaces/identity/definitions.ts +++ b/tee-worker/client-api/parachain-api/prepare-build/interfaces/identity/definitions.ts @@ -53,6 +53,7 @@ export default { "Polygon", "Arbitrum", "Solana", + "Combo", ], }, LitentryValidationData: { diff --git a/tee-worker/client-api/parachain-api/prepare-build/interfaces/vc/definitions.ts b/tee-worker/client-api/parachain-api/prepare-build/interfaces/vc/definitions.ts index ac4232aaff..5e863a2043 100644 --- a/tee-worker/client-api/parachain-api/prepare-build/interfaces/vc/definitions.ts +++ b/tee-worker/client-api/parachain-api/prepare-build/interfaces/vc/definitions.ts @@ -34,14 +34,20 @@ export default { TokenHoldingAmount: "Web3TokenType", PlatformUser: "PlatformUserType", NftHolder: "Web3NftType", - Dynamic: "([u8;20],Bytes)", + Dynamic: "DynamicParams", }, }, AssertionSupportedNetwork: { - _enum: ["Litentry", "Litmus", "LitentryRococo", "Polkadot", "Kusama", "Khala", "Ethereum", "TestNet"], + _enum: ["Polkadot", "Kusama", "Litentry", "Litmus", "__UnsupportedLitentryRococo", "Khala", "__UnsupportedSubstrateTestnet", "Ethereum"], + }, + DynamicParams: { + smart_contract_id: "[u8;20]", + smart_contract_params: "Option", + return_log: "bool", }, RequestVCResult: { vc_payload: "AesOutput", + vc_logs: "Option", pre_mutated_id_graph: "AesOutput", pre_id_graph_hash: "H256", }, @@ -230,15 +236,17 @@ export default { "Cro", "Inj", "Bean", + "An", + "Tuna", ], }, // PlatformUserType PlatformUserType: { - _enum: ["KaratDaoUser", "MagicCraftStakingUser"], + _enum: ["KaratDao", "MagicCraftStaking", "DarenMarket"], }, // Web3NftType Web3NftType: { - _enum: ["WeirdoGhostGang", "Club3Sbt"], + _enum: ["WeirdoGhostGang", "Club3Sbt", "MFan", "Mvp"], }, }, }; diff --git a/tee-worker/client-api/parachain-api/src/index.ts b/tee-worker/client-api/parachain-api/src/index.ts index 170c11a89c..4778713df8 100644 --- a/tee-worker/client-api/parachain-api/src/index.ts +++ b/tee-worker/client-api/parachain-api/src/index.ts @@ -17,3 +17,24 @@ import { default as vc } from "../build/interfaces/vc/definitions"; import { default as trusted_operations } from "../build/interfaces/trusted_operations/definitions"; import { default as sidechain } from "../build/interfaces/sidechain/definitions"; export { identity, vc, trusted_operations, sidechain }; + +// Export handy types +import type { LitentryIdentity, Web3Network } from "../build/interfaces/identity/types"; + +export type SubstrateNetwork = Extract< + Web3Network["type"], + "Polkadot" | "Kusama" | "Litentry" | "Litmus" | "LitentryRococo" | "Khala" | "SubstrateTestnet" +>; + +export type EvmNetwork = Extract; + +export type SolanaNetwork = Extract; + +export type BitcoinNetwork = Exclude; + +export type Web2Network = Exclude; + +/** + * Identities that can be used as prime identity to own an idGraph. + */ +export type PrimeIdentity = Extract; diff --git a/tee-worker/client-api/sidechain-api/CHANGELOG.md b/tee-worker/client-api/sidechain-api/CHANGELOG.md new file mode 100644 index 0000000000..ea5bda58c6 --- /dev/null +++ b/tee-worker/client-api/sidechain-api/CHANGELOG.md @@ -0,0 +1,34 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.9.18-10] - 2024-07-16 + +Align version with [parachain-release v0.9.18-10](https://github.com/litentry/litentry-parachain/releases/tag/v0.9.18-10) + +## [0.0.2-10] - 2024-07-15 + +Matching version for [parachain-release v0.9.18-10](https://github.com/litentry/litentry-parachain/releases/tag/v0.9.18-10) + +## [0.0.2-next.8] - 2024-07-12 + +Routinely update + +## [0.0.2-next.5] - 2024-07-02 + +Routinely update + +## [0.0.2-next.4] - 2024-06-13 + +### Changed + +- `package.json`: add `module` entry and mark it as side-effects free. + +## [0.0.2-next.3] - 2024-06-12 + +- Routinary update diff --git a/tee-worker/client-api/sidechain-api/README.md b/tee-worker/client-api/sidechain-api/README.md index 6764481882..97af7208eb 100644 --- a/tee-worker/client-api/sidechain-api/README.md +++ b/tee-worker/client-api/sidechain-api/README.md @@ -32,6 +32,8 @@ Versions in the pattern of `x.x.x-next.x` feature the most recent code version t 1. [Update your published package version number](https://docs.npmjs.com/updating-your-published-package-version-number) +1. Update the `CHANGELOG.md` file. + 1. Build the package ```s diff --git a/tee-worker/client-api/sidechain-api/package.json b/tee-worker/client-api/sidechain-api/package.json index bcbfeb3710..dfee472ad9 100644 --- a/tee-worker/client-api/sidechain-api/package.json +++ b/tee-worker/client-api/sidechain-api/package.json @@ -3,7 +3,9 @@ "type": "module", "license": "ISC", "main": "dist/src/index.js", - "version": "0.0.1-1", + "module": "dist/src/index.js", + "sideEffects": false, + "version": "0.9.18-10", "scripts": { "clean": "rm -rf dist build node_modules", "update-metadata": "../../bin/litentry-cli print-sgx-metadata-raw > prepare-build/litentry-sidechain-metadata.json", diff --git a/tee-worker/core-primitives/enclave-api/ffi/src/lib.rs b/tee-worker/core-primitives/enclave-api/ffi/src/lib.rs index 312582468e..a0248337be 100644 --- a/tee-worker/core-primitives/enclave-api/ffi/src/lib.rs +++ b/tee-worker/core-primitives/enclave-api/ffi/src/lib.rs @@ -243,7 +243,6 @@ extern "C" { pub fn migrate_shard( eid: sgx_enclave_id_t, retval: *mut sgx_status_t, - old_shard: *const u8, new_shard: *const u8, shard_size: u32, ) -> sgx_status_t; diff --git a/tee-worker/core-primitives/enclave-api/src/enclave_base.rs b/tee-worker/core-primitives/enclave-api/src/enclave_base.rs index 342e5060de..98ccb7c177 100644 --- a/tee-worker/core-primitives/enclave-api/src/enclave_base.rs +++ b/tee-worker/core-primitives/enclave-api/src/enclave_base.rs @@ -80,7 +80,7 @@ pub trait EnclaveBase: Send + Sync + 'static { fn get_fingerprint(&self) -> EnclaveResult; // litentry - fn migrate_shard(&self, old_shard: Vec, new_shard: Vec) -> EnclaveResult<()>; + fn migrate_shard(&self, new_shard: Vec) -> EnclaveResult<()>; } /// EnclaveApi implementation for Enclave struct @@ -369,16 +369,15 @@ mod impl_ffi { Ok(mr_enclave.into()) } - fn migrate_shard(&self, old_shard: Vec, new_shard: Vec) -> EnclaveResult<()> { + fn migrate_shard(&self, new_shard: Vec) -> EnclaveResult<()> { let mut retval = sgx_status_t::SGX_SUCCESS; let result = unsafe { ffi::migrate_shard( self.eid, &mut retval, - old_shard.as_ptr(), new_shard.as_ptr(), - old_shard.len() as u32, + new_shard.len() as u32, ) }; diff --git a/tee-worker/core-primitives/node-api/metadata/src/lib.rs b/tee-worker/core-primitives/node-api/metadata/src/lib.rs index 2a16549e50..1705582b90 100644 --- a/tee-worker/core-primitives/node-api/metadata/src/lib.rs +++ b/tee-worker/core-primitives/node-api/metadata/src/lib.rs @@ -20,7 +20,8 @@ #![cfg_attr(not(feature = "std"), no_std)] use crate::{ - error::Result, pallet_balances::BalancesCallIndexes, pallet_imp::IMPCallIndexes, + error::Result, pallet_balances::BalancesCallIndexes, + pallet_evm_assertion::EvmAssertionsCallIndexes, pallet_imp::IMPCallIndexes, pallet_proxy::ProxyCallIndexes, pallet_system::SystemConstants, pallet_teebag::TeebagCallIndexes, pallet_timestamp::TimestampCallIndexes, pallet_utility::UtilityCallIndexes, pallet_vcmp::VCMPCallIndexes, @@ -33,6 +34,7 @@ pub use itp_api_client_types::{Metadata, MetadataError}; pub mod error; pub mod pallet_balances; +pub mod pallet_evm_assertion; pub mod pallet_imp; pub mod pallet_proxy; pub mod pallet_system; @@ -55,6 +57,7 @@ pub trait NodeMetadataTrait: + ProxyCallIndexes + BalancesCallIndexes + TimestampCallIndexes + + EvmAssertionsCallIndexes { } @@ -66,7 +69,8 @@ impl< + UtilityCallIndexes + ProxyCallIndexes + BalancesCallIndexes - + TimestampCallIndexes, + + TimestampCallIndexes + + EvmAssertionsCallIndexes, > NodeMetadataTrait for T { } diff --git a/tee-worker/core-primitives/node-api/metadata/src/metadata_mocks.rs b/tee-worker/core-primitives/node-api/metadata/src/metadata_mocks.rs index 83df6dfc43..adf13c8cf8 100644 --- a/tee-worker/core-primitives/node-api/metadata/src/metadata_mocks.rs +++ b/tee-worker/core-primitives/node-api/metadata/src/metadata_mocks.rs @@ -16,7 +16,8 @@ */ use crate::{ - error::Result, pallet_balances::BalancesCallIndexes, pallet_imp::IMPCallIndexes, + error::Result, pallet_balances::BalancesCallIndexes, + pallet_evm_assertion::EvmAssertionsCallIndexes, pallet_imp::IMPCallIndexes, pallet_proxy::ProxyCallIndexes, pallet_system::SystemConstants, pallet_teebag::TeebagCallIndexes, pallet_timestamp::TimestampCallIndexes, pallet_utility::UtilityCallIndexes, pallet_vcmp::VCMPCallIndexes, runtime_call::RuntimeCall, @@ -39,8 +40,8 @@ pub struct NodeMetadataMock { // litentry // teebag teebag_module: u8, - set_scheduled_enclave: u8, - remove_scheduled_enclave: u8, + force_add_authorized_enclave: u8, + force_remove_authorized_enclave: u8, register_enclave: u8, unregister_enclave: u8, register_quoting_enclave: u8, @@ -64,6 +65,10 @@ pub struct NodeMetadataMock { vcmp_request_vc: u8, vcmp_vc_issued: u8, vcmp_some_error: u8, + // EVM Assertion + evm_assertions_module: u8, + evm_assertions_store_assertion: u8, + evm_assertions_void_assertion: u8, utility_module: u8, utility_batch: u8, @@ -90,8 +95,8 @@ impl NodeMetadataMock { NodeMetadataMock { // litentry teebag_module: 50u8, - set_scheduled_enclave: 0u8, - remove_scheduled_enclave: 1u8, + force_add_authorized_enclave: 0u8, + force_remove_authorized_enclave: 1u8, register_enclave: 2u8, unregister_enclave: 3u8, register_quoting_enclave: 4u8, @@ -116,6 +121,10 @@ impl NodeMetadataMock { vcmp_vc_issued: 3u8, vcmp_some_error: 9u8, + evm_assertions_module: 76u8, + evm_assertions_store_assertion: 77u8, + evm_assertions_void_assertion: 78u8, + utility_module: 80u8, utility_batch: 0u8, utility_as_derivative: 1u8, @@ -139,11 +148,11 @@ impl NodeMetadataMock { } impl TeebagCallIndexes for NodeMetadataMock { - fn set_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]> { - Ok([self.teebag_module, self.set_scheduled_enclave]) + fn force_add_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.teebag_module, self.force_add_authorized_enclave]) } - fn remove_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]> { - Ok([self.teebag_module, self.remove_scheduled_enclave]) + fn force_remove_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.teebag_module, self.force_remove_authorized_enclave]) } fn register_enclave_call_indexes(&self) -> Result<[u8; 2]> { Ok([self.teebag_module, self.register_enclave]) @@ -291,3 +300,13 @@ impl TimestampCallIndexes for NodeMetadataMock { Ok([self.timestamp_module, self.timestamp_set]) } } + +impl EvmAssertionsCallIndexes for NodeMetadataMock { + fn store_assertion_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.evm_assertions_module, self.evm_assertions_store_assertion]) + } + + fn void_assertion_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.evm_assertions_module, self.evm_assertions_void_assertion]) + } +} diff --git a/tee-worker/core-primitives/node-api/metadata/src/pallet_evm_assertion.rs b/tee-worker/core-primitives/node-api/metadata/src/pallet_evm_assertion.rs new file mode 100644 index 0000000000..21ff39977a --- /dev/null +++ b/tee-worker/core-primitives/node-api/metadata/src/pallet_evm_assertion.rs @@ -0,0 +1,36 @@ +/* + Copyright 2021 Integritee AG and Supercomputing Systems AG + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +use crate::{error::Result, NodeMetadata}; + +/// Pallet name: +const EVM_ASSERTION: &str = "EvmAssertions"; + +pub trait EvmAssertionsCallIndexes { + fn store_assertion_call_indexes(&self) -> Result<[u8; 2]>; + fn void_assertion_call_indexes(&self) -> Result<[u8; 2]>; +} + +impl EvmAssertionsCallIndexes for NodeMetadata { + fn store_assertion_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(EVM_ASSERTION, "store_assertion") + } + + fn void_assertion_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(EVM_ASSERTION, "void_assertion") + } +} diff --git a/tee-worker/core-primitives/node-api/metadata/src/pallet_teebag.rs b/tee-worker/core-primitives/node-api/metadata/src/pallet_teebag.rs index 0dc73cfb25..24b5e130fc 100644 --- a/tee-worker/core-primitives/node-api/metadata/src/pallet_teebag.rs +++ b/tee-worker/core-primitives/node-api/metadata/src/pallet_teebag.rs @@ -21,9 +21,9 @@ pub const TEEBAG: &str = "Teebag"; // we only list the extrinsics that we care pub trait TeebagCallIndexes { - fn set_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]>; + fn force_add_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]>; - fn remove_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]>; + fn force_remove_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]>; fn register_enclave_call_indexes(&self) -> Result<[u8; 2]>; @@ -41,11 +41,11 @@ pub trait TeebagCallIndexes { } impl TeebagCallIndexes for NodeMetadata { - fn set_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]> { - self.call_indexes(TEEBAG, "set_scheduled_enclave") + fn force_add_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(TEEBAG, "force_add_authorized_enclave") } - fn remove_scheduled_enclave_call_indexes(&self) -> Result<[u8; 2]> { - self.call_indexes(TEEBAG, "remove_scheduled_enclave") + fn force_remove_authorized_enclave_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(TEEBAG, "force_remove_authorized_enclave") } fn register_enclave_call_indexes(&self) -> Result<[u8; 2]> { self.call_indexes(TEEBAG, "register_enclave") diff --git a/tee-worker/core-primitives/settings/src/lib.rs b/tee-worker/core-primitives/settings/src/lib.rs index 61b984114c..49233bfc08 100644 --- a/tee-worker/core-primitives/settings/src/lib.rs +++ b/tee-worker/core-primitives/settings/src/lib.rs @@ -46,7 +46,6 @@ pub mod files { pub const TARGET_B_PARENTCHAIN_LIGHT_CLIENT_DB_PATH: &str = "target_b_lcdb"; // litentry - pub const SCHEDULED_ENCLAVE_FILE: &str = "scheduled_enclave_sealed.bin"; pub const ASSERTIONS_FILE: &str = "assertions_sealed.bin"; pub const RA_DUMP_CERT_DER_FILE: &str = "ra_dump_cert.der"; diff --git a/tee-worker/core-primitives/stf-executor/src/enclave_signer.rs b/tee-worker/core-primitives/stf-executor/src/enclave_signer.rs index 9de7c2bfa0..a4d4fd8c01 100644 --- a/tee-worker/core-primitives/stf-executor/src/enclave_signer.rs +++ b/tee-worker/core-primitives/stf-executor/src/enclave_signer.rs @@ -32,7 +32,7 @@ use itp_stf_primitives::{ }; use itp_stf_state_observer::traits::ObserveState; use itp_top_pool_author::traits::AuthorApi; -use itp_types::{Index, ShardIdentifier}; +use itp_types::{Index, MrEnclave, ShardIdentifier}; use sp_core::{ed25519::Pair as Ed25519Pair, Pair}; use std::{boxed::Box, sync::Arc, vec::Vec}; @@ -115,12 +115,16 @@ where self.get_enclave_call_signing_key().map(|key| key.public().into()) } + fn get_mrenclave(&self) -> Result { + Ok(self.ocall_api.get_mrenclave_of_self().map(|m| m.m)?) + } + fn sign_call_with_self>( &self, trusted_call: &TC, shard: &ShardIdentifier, ) -> Result { - let mr_enclave = self.ocall_api.get_mrenclave_of_self()?; + let mrenclave = self.get_mrenclave()?; let enclave_account = self.get_enclave_account()?; let enclave_call_signing_key = self.get_enclave_call_signing_key()?; @@ -136,7 +140,7 @@ where Ok(trusted_call.sign( &KeyPair::Ed25519(Box::new(enclave_call_signing_key)), adjusted_nonce, - &mr_enclave.m, + &mrenclave, shard, )) } diff --git a/tee-worker/core-primitives/stf-executor/src/mocks.rs b/tee-worker/core-primitives/stf-executor/src/mocks.rs index 39df4eda8a..d328a2e24e 100644 --- a/tee-worker/core-primitives/stf-executor/src/mocks.rs +++ b/tee-worker/core-primitives/stf-executor/src/mocks.rs @@ -28,7 +28,7 @@ use itp_stf_primitives::{ traits::TrustedCallSigning, types::{AccountId, KeyPair, ShardIdentifier, TrustedOperationOrHash}, }; -use itp_types::H256; +use itp_types::{MrEnclave, H256}; use sp_core::Pair; use sp_runtime::traits::Header as HeaderTrait; #[cfg(feature = "std")] @@ -134,6 +134,10 @@ impl StfEnclaveSigning for StfEnclaveSigne Ok(self.signer.public().into()) } + fn get_mrenclave(&self) -> Result { + Ok(self.mr_enclave) + } + fn sign_call_with_self>( &self, trusted_call: &TC, diff --git a/tee-worker/core-primitives/stf-executor/src/traits.rs b/tee-worker/core-primitives/stf-executor/src/traits.rs index f8dd183aa2..62e788141a 100644 --- a/tee-worker/core-primitives/stf-executor/src/traits.rs +++ b/tee-worker/core-primitives/stf-executor/src/traits.rs @@ -23,7 +23,7 @@ use itp_stf_primitives::{ traits::TrustedCallSigning, types::{AccountId, ShardIdentifier, TrustedOperation}, }; -use itp_types::H256; +use itp_types::{MrEnclave, H256}; use sp_runtime::traits::Header as HeaderTrait; use std::{time::Duration, vec::Vec}; @@ -42,6 +42,8 @@ where { fn get_enclave_account(&self) -> Result; + fn get_mrenclave(&self) -> Result; + fn sign_call_with_self>( &self, trusted_call: &TC, diff --git a/tee-worker/core-primitives/stf-primitives/src/traits.rs b/tee-worker/core-primitives/stf-primitives/src/traits.rs index 7b473d67f7..404db9a5ff 100644 --- a/tee-worker/core-primitives/stf-primitives/src/traits.rs +++ b/tee-worker/core-primitives/stf-primitives/src/traits.rs @@ -19,7 +19,7 @@ use alloc::vec::Vec; use codec::{Decode, Encode}; use core::fmt::Debug; use itp_sgx_runtime_primitives::types::Index; -use litentry_primitives::Identity; +use litentry_primitives::{Identity, MrEnclave}; use sp_runtime::transaction_validity::{TransactionValidityError, ValidTransaction}; /// checks authorization of stf getters @@ -69,6 +69,8 @@ where fn get_enclave_account(&self) -> Result; + fn get_mrenclave(&self) -> Result; + fn get_default_shard(&self) -> ShardIdentifier; fn sign_call_with_self>( diff --git a/tee-worker/core-primitives/stf-state-handler/src/handle_state.rs b/tee-worker/core-primitives/stf-state-handler/src/handle_state.rs index 8dae3c1f43..564679e6ca 100644 --- a/tee-worker/core-primitives/stf-state-handler/src/handle_state.rs +++ b/tee-worker/core-primitives/stf-state-handler/src/handle_state.rs @@ -73,11 +73,6 @@ pub trait HandleState { /// Use in cases where the previous state is of no interest. Otherwise use `load_for_mutation` and `write_after_mutation`. fn reset(&self, state: Self::StateT, shard: &ShardIdentifier) -> Result; - // litentry - /// Migrate state from old shard to new shard - fn migrate_shard( - &self, - old_shard: ShardIdentifier, - new_shard: ShardIdentifier, - ) -> Result; + /// Force migrate state to new shard + fn migrate_shard(&self, new_shard: ShardIdentifier) -> Result; } diff --git a/tee-worker/core-primitives/stf-state-handler/src/state_handler.rs b/tee-worker/core-primitives/stf-state-handler/src/state_handler.rs index 564c5ed8d6..aded5198b4 100644 --- a/tee-worker/core-primitives/stf-state-handler/src/state_handler.rs +++ b/tee-worker/core-primitives/stf-state-handler/src/state_handler.rs @@ -228,11 +228,19 @@ where self.write_after_mutation(state, state_write_lock, shard) } - fn migrate_shard( - &self, - old_shard: ShardIdentifier, - new_shard: ShardIdentifier, - ) -> Result { + fn migrate_shard(&self, new_shard: ShardIdentifier) -> Result { + if self.shard_exists(&new_shard)? { + let (_, state_hash) = self.load_cloned(&new_shard)?; + return Ok(state_hash) + } + let old_shard = match self.list_shards()? { + shards if shards.len() == 1 => shards[0], + _ => + return Err(Error::Other( + "Cannot migrate shard. There is more than 1 shard in the list".into(), + )), + }; + let (old_shard_state, old_shard_state_hash) = self.load_cloned(&old_shard)?; self.reset(old_shard_state, &new_shard)?; diff --git a/tee-worker/core-primitives/substrate-sgx/sp-io/src/lib.rs b/tee-worker/core-primitives/substrate-sgx/sp-io/src/lib.rs index 6962f6c164..4890d03c97 100644 --- a/tee-worker/core-primitives/substrate-sgx/sp-io/src/lib.rs +++ b/tee-worker/core-primitives/substrate-sgx/sp-io/src/lib.rs @@ -169,7 +169,7 @@ pub mod storage { pub fn clear(key: &[u8]) { with_externalities(|ext| { if ext.remove(key).is_none() { - info!("Tried to clear storage that was not existing"); + debug!("Tried to clear storage that was not existing"); } }); } diff --git a/tee-worker/core-primitives/test/src/mock/handle_state_mock.rs b/tee-worker/core-primitives/test/src/mock/handle_state_mock.rs index 3776a0d9a9..9c8710935d 100644 --- a/tee-worker/core-primitives/test/src/mock/handle_state_mock.rs +++ b/tee-worker/core-primitives/test/src/mock/handle_state_mock.rs @@ -56,11 +56,8 @@ impl HandleState for HandleStateMock { self.reset(StfState::default(), &shard) } - fn migrate_shard( - &self, - old_shard: ShardIdentifier, - new_shard: ShardIdentifier, - ) -> Result { + fn migrate_shard(&self, new_shard: ShardIdentifier) -> Result { + let old_shard = *self.state_map.read().unwrap().keys().next().unwrap(); let (state, _) = self.load_cloned(&old_shard)?; self.reset(state, &new_shard) } @@ -228,7 +225,7 @@ pub mod tests { state.insert(key.encode(), value.encode()); state_handler.write_after_mutation(state, lock, &old_shard).unwrap(); - state_handler.migrate_shard(old_shard, new_shard).unwrap(); + state_handler.migrate_shard(new_shard).unwrap(); let (new_state, _) = state_handler.load_cloned(&new_shard).unwrap(); let inserted_value = new_state.get(key.encode().as_slice()).expect("value for key should exist"); diff --git a/tee-worker/core-primitives/top-pool-author/src/author.rs b/tee-worker/core-primitives/top-pool-author/src/author.rs index 0598c4b835..cf01139dd9 100644 --- a/tee-worker/core-primitives/top-pool-author/src/author.rs +++ b/tee-worker/core-primitives/top-pool-author/src/author.rs @@ -330,7 +330,7 @@ impl< }) { error!("Could not send broadcasted request, reason: {:?}", e); } else { - info!("Broadcast request OK, hash = {}", hash); + debug!("Broadcast request OK, hash = {}", hash); } } result diff --git a/tee-worker/core-primitives/types/src/lib.rs b/tee-worker/core-primitives/types/src/lib.rs index 8d29da6071..a4d58a2969 100644 --- a/tee-worker/core-primitives/types/src/lib.rs +++ b/tee-worker/core-primitives/types/src/lib.rs @@ -29,8 +29,8 @@ pub mod storage; pub use itp_sgx_runtime_primitives::types::*; pub use litentry_primitives::{ - Assertion, AttestationType, DecryptableRequest, Enclave, EnclaveFingerprint, MrEnclave, - SidechainBlockNumber, WorkerType, + Assertion, AttestationType, DcapProvider, DecryptableRequest, Enclave, EnclaveFingerprint, + MrEnclave, SidechainBlockNumber, WorkerType, }; pub use sp_core::{crypto::AccountId32 as AccountId, H256}; diff --git a/tee-worker/core-primitives/types/src/parentchain/events.rs b/tee-worker/core-primitives/types/src/parentchain/events.rs index 19c8b5a6cb..f6b40d1339 100644 --- a/tee-worker/core-primitives/types/src/parentchain/events.rs +++ b/tee-worker/core-primitives/types/src/parentchain/events.rs @@ -1,16 +1,16 @@ use super::alloc::{format, vec::Vec}; use crate::{ AccountId, Assertion, Balance, BlockNumber, Hash, MrEnclave, RsaRequest, ShardIdentifier, - SidechainBlockNumber, WorkerType, + WorkerType, }; use codec::{Decode, Encode}; use core::fmt::Debug; -use itp_utils::stringify::account_id_to_string; +use itp_utils::{hex::ToHexPrefixed, stringify::account_id_to_string}; + use sp_core::H160; use substrate_api_client::ac_node_api::StaticEvent; // System pallet events - #[derive(Encode, Decode, Debug)] pub struct ExtrinsicSuccess; @@ -79,50 +79,25 @@ impl StaticEvent for ParentchainBlockProcessed { } #[derive(Encode, Decode, Debug)] -pub struct ScheduledEnclaveSet { +pub struct EnclaveUnauthorized { pub worker_type: WorkerType, - pub sidechain_block_number: SidechainBlockNumber, pub mrenclave: MrEnclave, } -impl core::fmt::Display for ScheduledEnclaveSet { +impl core::fmt::Display for EnclaveUnauthorized { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { let message = format!( - "[{}:{}] :: worker_type: {:?}, sidechain_block_number: {}, mrenclave: {:?}", - ScheduledEnclaveSet::PALLET, - ScheduledEnclaveSet::EVENT, + "EnclaveUnauthorized :: worker_type: {:?}, mrenclave: {}", self.worker_type, - self.sidechain_block_number, - self.mrenclave - ); - write!(f, "{}", message) - } -} - -impl StaticEvent for ScheduledEnclaveSet { - const PALLET: &'static str = "Teebag"; - const EVENT: &'static str = "ScheduledEnclaveSet"; -} - -#[derive(Encode, Decode, Debug)] -pub struct ScheduledEnclaveRemoved { - pub worker_type: WorkerType, - pub sidechain_block_number: SidechainBlockNumber, -} - -impl core::fmt::Display for ScheduledEnclaveRemoved { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - let message = format!( - "ScheduledEnclaveRemoved :: worker_type: {:?}, sidechain_block_number: {}", - self.worker_type, self.sidechain_block_number + self.mrenclave.to_hex() ); write!(f, "{}", message) } } -impl StaticEvent for ScheduledEnclaveRemoved { +impl StaticEvent for EnclaveUnauthorized { const PALLET: &'static str = "Teebag"; - const EVENT: &'static str = "ScheduledEnclaveRemoved"; + const EVENT: &'static str = "EnclaveUnauthorized"; } // IdentityManagement events diff --git a/tee-worker/core-primitives/types/src/parentchain/mod.rs b/tee-worker/core-primitives/types/src/parentchain/mod.rs index d8c2d86257..723127eafa 100644 --- a/tee-worker/core-primitives/types/src/parentchain/mod.rs +++ b/tee-worker/core-primitives/types/src/parentchain/mod.rs @@ -22,13 +22,13 @@ use alloc::vec::Vec; use codec::{Decode, Encode}; use core::fmt::Debug; use events::{ - ActivateIdentityRequested, DeactivateIdentityRequested, LinkIdentityRequested, - OpaqueTaskPosted, ScheduledEnclaveRemoved, ScheduledEnclaveSet, VCRequested, + ActivateIdentityRequested, DeactivateIdentityRequested, EnclaveUnauthorized, + LinkIdentityRequested, OpaqueTaskPosted, VCRequested, }; use itp_stf_primitives::traits::{IndirectExecutor, TrustedCallVerification}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -use sp_core::{bounded::alloc, H256}; +use sp_core::{bounded::alloc, H160, H256}; use sp_runtime::{generic::Header as HeaderG, traits::BlakeTwo256, MultiAddress, MultiSignature}; use self::events::ParentchainBlockProcessed; @@ -107,11 +107,7 @@ pub trait FilterEvents { fn get_activate_identity_events(&self) -> Result, Self::Error>; - fn get_scheduled_enclave_set_events(&self) -> Result, Self::Error>; - - fn get_scheduled_enclave_removed_events( - &self, - ) -> Result, Self::Error>; + fn get_enclave_unauthorized_events(&self) -> Result, Self::Error>; fn get_opaque_task_posted_events(&self) -> Result, Self::Error>; @@ -128,6 +124,8 @@ pub enum ExtrinsicStatus { Failed, } +pub type ProcessedEventsArtifacts = (Vec, Vec, Vec); + pub trait HandleParentchainEvents where Executor: IndirectExecutor, @@ -137,7 +135,7 @@ where &self, executor: &Executor, events: impl FilterEvents, - ) -> Result, Error>; + ) -> Result; } #[derive(Debug)] @@ -147,8 +145,7 @@ pub enum ParentchainEventProcessingError { DeactivateIdentityFailure, ActivateIdentityFailure, VCRequestedFailure, - ScheduledEnclaveSetFailure, - ScheduledEnclaveRemovedFailure, + EnclaveUnauthorizedFailure, OpaqueTaskPostedFailure, AssertionCreatedFailure, ParentchainBlockProcessedFailure, @@ -167,10 +164,8 @@ impl core::fmt::Display for ParentchainEventProcessingError { "Parentchain Event Processing Error: ActivateIdentityFailure", ParentchainEventProcessingError::VCRequestedFailure => "Parentchain Event Processing Error: VCRequestedFailure", - ParentchainEventProcessingError::ScheduledEnclaveSetFailure => - "Parentchain Event Processing Error: ScheduledEnclaveSetFailure", - ParentchainEventProcessingError::ScheduledEnclaveRemovedFailure => - "Parentchain Event Processing Error: ScheduledEnclaveRemovedFailure", + ParentchainEventProcessingError::EnclaveUnauthorizedFailure => + "Parentchain Event Processing Error: EnclaveUnauthorizedFailure", ParentchainEventProcessingError::OpaqueTaskPostedFailure => "Parentchain Event Processing Error: OpaqueTaskPostedFailure", ParentchainEventProcessingError::AssertionCreatedFailure => diff --git a/tee-worker/core/direct-rpc-server/src/rpc_connection_registry.rs b/tee-worker/core/direct-rpc-server/src/rpc_connection_registry.rs index 001f1728b5..9b114e849b 100644 --- a/tee-worker/core/direct-rpc-server/src/rpc_connection_registry.rs +++ b/tee-worker/core/direct-rpc-server/src/rpc_connection_registry.rs @@ -76,7 +76,7 @@ where rpc_response: RpcResponse, force_wait: ForceWait, ) { - log::info!("Store hash {:?} to connection registry, force_wait: {}", hash, force_wait); + log::debug!("Store hash {:?} to connection registry, force_wait: {}", hash, force_wait); let mut map = self.connection_map.write().expect("Lock poisoning"); map.insert(hash, (connection, rpc_response, force_wait)); } diff --git a/tee-worker/core/direct-rpc-server/src/rpc_responder.rs b/tee-worker/core/direct-rpc-server/src/rpc_responder.rs index 1401b701b4..904d9c1e9b 100644 --- a/tee-worker/core/direct-rpc-server/src/rpc_responder.rs +++ b/tee-worker/core/direct-rpc-server/src/rpc_responder.rs @@ -75,7 +75,7 @@ where hash: Hash, status_update: TrustedOperationStatus, ) -> DirectRpcResult<()> { - info!("updating status event, hash: {}, status: {:?}", hash.to_hex(), status_update); + debug!("updating status event, hash: {}, status: {:?}", hash.to_hex(), status_update); // withdraw removes it from the registry let (connection_token, rpc_response, force_wait) = self @@ -167,7 +167,7 @@ where encoded_value: Vec, force_wait: bool, ) -> DirectRpcResult<()> { - info!( + debug!( "updating connection state for hash {:?}: encoded_value {:?}, force_wait: {:?}", hash, encoded_value.to_hex(), diff --git a/tee-worker/core/parentchain/block-importer/src/block_importer.rs b/tee-worker/core/parentchain/block-importer/src/block_importer.rs index 65e61804c5..efbb129429 100644 --- a/tee-worker/core/parentchain/block-importer/src/block_importer.rs +++ b/tee-worker/core/parentchain/block-importer/src/block_importer.rs @@ -184,8 +184,8 @@ impl< &raw_events, self.ocall_api.clone(), ) { - Ok(Some(confirm_processed_parentchain_block_call)) => { - calls.push(confirm_processed_parentchain_block_call); + Ok(Some(opaque_calls)) => { + calls.extend(opaque_calls); }, Ok(None) => trace!("omitting confirmation call to non-integritee parentchain"), Err(e) => error!("[{:?}] Error executing relevant events: {:?}", id, e), diff --git a/tee-worker/core/parentchain/indirect-calls-executor/Cargo.toml b/tee-worker/core/parentchain/indirect-calls-executor/Cargo.toml index fad0ceb26e..c798c99264 100644 --- a/tee-worker/core/parentchain/indirect-calls-executor/Cargo.toml +++ b/tee-worker/core/parentchain/indirect-calls-executor/Cargo.toml @@ -42,7 +42,6 @@ sp-runtime = { default-features = false, git = "https://github.com/paritytech/su # litentry itp-utils = { path = "../../../core-primitives/utils", default-features = false } -lc-scheduled-enclave = { path = "../../../litentry/core/scheduled-enclave", default-features = false, optional = true } litentry-primitives = { path = "../../../litentry/primitives", default-features = false } parachain-core-primitives = { package = "core-primitives", path = "../../../../primitives/core", default-features = false } sp-std = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } @@ -84,7 +83,6 @@ std = [ "itp-utils/std", "parachain-core-primitives/std", "sp-std/std", - "lc-scheduled-enclave/std", ] sgx = [ "sgx_tstd", @@ -98,5 +96,4 @@ sgx = [ "thiserror_sgx", # litentry "litentry-primitives/sgx", - "lc-scheduled-enclave/sgx", ] diff --git a/tee-worker/core/parentchain/indirect-calls-executor/src/error.rs b/tee-worker/core/parentchain/indirect-calls-executor/src/error.rs index 33e346bbe2..e5e51eae13 100644 --- a/tee-worker/core/parentchain/indirect-calls-executor/src/error.rs +++ b/tee-worker/core/parentchain/indirect-calls-executor/src/error.rs @@ -20,7 +20,6 @@ use crate::sgx_reexport_prelude::*; pub use litentry_primitives::{ErrorDetail, IMPError, VCMPError}; use itp_types::parentchain::ParentchainEventProcessingError; -use lc_scheduled_enclave::error::Error as ScheduledEnclaveError; use sgx_types::sgx_status_t; use sp_runtime::traits::LookupError; use std::{boxed::Box, format, string::String}; @@ -52,8 +51,6 @@ pub enum Error { VCMPHandlingError(VCMPError), #[error("BatchAll handling error")] BatchAllHandlingError, - #[error("ScheduledEnclave Error: {0:?}")] - ImportScheduledEnclave(ScheduledEnclaveError), #[error("AssertionCreated handling error: {0:?}")] AssertionCreatedHandling(String), } @@ -105,9 +102,3 @@ impl From for Error { Self::VCMPHandlingError(e) } } - -impl From for Error { - fn from(e: ScheduledEnclaveError) -> Self { - Self::ImportScheduledEnclave(e) - } -} diff --git a/tee-worker/core/parentchain/indirect-calls-executor/src/executor.rs b/tee-worker/core/parentchain/indirect-calls-executor/src/executor.rs index a59001b150..61ced37b8a 100644 --- a/tee-worker/core/parentchain/indirect-calls-executor/src/executor.rs +++ b/tee-worker/core/parentchain/indirect-calls-executor/src/executor.rs @@ -30,7 +30,8 @@ use core::marker::PhantomData; use itp_api_client_types::StaticEvent; use itp_enclave_metrics::EnclaveMetric; use itp_node_api::metadata::{ - pallet_teebag::TeebagCallIndexes, provider::AccessNodeMetadata, NodeMetadataTrait, + pallet_evm_assertion::EvmAssertionsCallIndexes, pallet_teebag::TeebagCallIndexes, + provider::AccessNodeMetadata, NodeMetadataTrait, }; use itp_ocall_api::EnclaveMetricsOCallApi; use itp_sgx_crypto::{key_repository::AccessKey, ShieldingCryptoDecrypt, ShieldingCryptoEncrypt}; @@ -42,7 +43,7 @@ use itp_stf_primitives::{ use itp_top_pool_author::traits::AuthorApi; use itp_types::{ parentchain::{events::ParentchainBlockProcessed, HandleParentchainEvents, ParentchainId}, - OpaqueCall, RsaRequest, ShardIdentifier, H256, + MrEnclave, OpaqueCall, RsaRequest, ShardIdentifier, H256, }; use log::*; use sp_core::blake2_256; @@ -149,7 +150,7 @@ impl< block: &ParentchainBlock, events: &[u8], metrics_api: Arc, - ) -> Result> + ) -> Result>> where ParentchainBlock: ParentchainBlockTrait, OCallApi: EnclaveMetricsOCallApi, @@ -166,7 +167,15 @@ impl< })? .ok_or_else(|| Error::Other("Could not create events from metadata".into()))?; - let processed_events = self.parentchain_event_handler.handle_events(self, events)?; + let (processed_events, successful_assertion_ids, failed_assertion_ids) = + self.parentchain_event_handler.handle_events(self, events)?; + let mut calls: Vec = Vec::new(); + if !successful_assertion_ids.is_empty() { + calls.extend(self.create_assertion_stored_call(successful_assertion_ids)?); + } + if !failed_assertion_ids.is_empty() { + calls.extend(self.create_assertion_voided_call(failed_assertion_ids)?); + } update_parentchain_events_processed_metrics(metrics_api, &processed_events); @@ -174,11 +183,12 @@ impl< if self.parentchain_id == ParentchainId::Litentry { // Include a processed parentchain block confirmation for each block. - Ok(Some(self.create_processed_parentchain_block_call::( + calls.push(self.create_processed_parentchain_block_call::( block_hash, processed_events, block_number, - )?)) + )?); + Ok(Some(calls)) } else { // fixme: send other type of confirmation here: https://github.com/integritee-network/worker/issues/1567 Ok(None) @@ -203,6 +213,34 @@ impl< // however, we should not forget it in case we need it later Ok(OpaqueCall::from_tuple(&(call, block_hash, block_number, root))) } + + fn create_assertion_stored_call( + &self, + assertion_ids: Vec, + ) -> Result> { + let call = self + .node_meta_data_provider + .get_from_metadata(|meta_data| meta_data.store_assertion_call_indexes())??; + let calls: Vec = assertion_ids + .into_iter() + .map(|id| OpaqueCall::from_tuple(&(call, id))) + .collect(); + Ok(calls) + } + + fn create_assertion_voided_call( + &self, + assertion_ids: Vec, + ) -> Result> { + let call = self + .node_meta_data_provider + .get_from_metadata(|meta_data| meta_data.void_assertion_call_indexes())??; + let calls: Vec = assertion_ids + .into_iter() + .map(|id| OpaqueCall::from_tuple(&(call, id))) + .collect(); + Ok(calls) + } } fn update_parentchain_events_processed_metrics( @@ -277,6 +315,10 @@ impl< Ok(self.stf_enclave_signer.get_enclave_account()?) } + fn get_mrenclave(&self) -> Result { + Ok(self.stf_enclave_signer.get_mrenclave()?) + } + fn get_default_shard(&self) -> ShardIdentifier { self.top_pool_author.list_handled_shards().first().copied().unwrap_or_default() } diff --git a/tee-worker/core/parentchain/indirect-calls-executor/src/mock.rs b/tee-worker/core/parentchain/indirect-calls-executor/src/mock.rs index 942a8ac8d5..bc63f95317 100644 --- a/tee-worker/core/parentchain/indirect-calls-executor/src/mock.rs +++ b/tee-worker/core/parentchain/indirect-calls-executor/src/mock.rs @@ -5,13 +5,13 @@ use itp_types::{ parentchain::{ events::{ ActivateIdentityRequested, AssertionCreated, DeactivateIdentityRequested, - LinkIdentityRequested, OpaqueTaskPosted, ScheduledEnclaveRemoved, ScheduledEnclaveSet, - VCRequested, + EnclaveUnauthorized, LinkIdentityRequested, OpaqueTaskPosted, VCRequested, }, - FilterEvents, HandleParentchainEvents, + FilterEvents, HandleParentchainEvents, ProcessedEventsArtifacts, }, RsaRequest, H256, }; +use sp_core::H160; use std::vec::Vec; pub struct TestEventCreator; @@ -57,13 +57,7 @@ impl FilterEvents for MockEvents { Ok(Vec::new()) } - fn get_scheduled_enclave_set_events(&self) -> Result, Self::Error> { - Ok(Vec::new()) - } - - fn get_scheduled_enclave_removed_events( - &self, - ) -> Result, Self::Error> { + fn get_enclave_unauthorized_events(&self) -> Result, Self::Error> { Ok(Vec::new()) } @@ -85,7 +79,15 @@ impl HandleParentchainEvents where Executor: IndirectExecutor, { - fn handle_events(&self, _: &Executor, _: impl FilterEvents) -> Result, Error> { - Ok(Vec::from([H256::default()])) + fn handle_events( + &self, + _: &Executor, + _: impl FilterEvents, + ) -> Result { + Ok(( + Vec::from([H256::default()]), + Vec::from([H160::default()]), + Vec::from([H160::default()]), + )) } } diff --git a/tee-worker/core/parentchain/indirect-calls-executor/src/traits.rs b/tee-worker/core/parentchain/indirect-calls-executor/src/traits.rs index 17536783e7..ada3007406 100644 --- a/tee-worker/core/parentchain/indirect-calls-executor/src/traits.rs +++ b/tee-worker/core/parentchain/indirect-calls-executor/src/traits.rs @@ -21,6 +21,7 @@ use core::fmt::Debug; use itp_ocall_api::EnclaveMetricsOCallApi; use itp_stf_primitives::traits::{IndirectExecutor, TrustedCallVerification}; use itp_types::{OpaqueCall, H256}; +use sp_core::H160; use sp_runtime::traits::{Block as ParentchainBlockTrait, Header}; use std::{sync::Arc, vec::Vec}; @@ -34,7 +35,7 @@ pub trait ExecuteIndirectCalls { block: &ParentchainBlock, events: &[u8], metrics_api: Arc, - ) -> Result> + ) -> Result>> where ParentchainBlock: ParentchainBlockTrait, OCallApi: EnclaveMetricsOCallApi; @@ -50,6 +51,10 @@ pub trait ExecuteIndirectCalls { ) -> Result where ParentchainBlock: ParentchainBlockTrait; + + fn create_assertion_stored_call(&self, assertion_ids: Vec) -> Result>; + + fn create_assertion_voided_call(&self, assertion_ids: Vec) -> Result>; } /// Trait that should be implemented on indirect calls to be executed. diff --git a/tee-worker/core/tls-websocket-server/src/connection.rs b/tee-worker/core/tls-websocket-server/src/connection.rs index 10266f9b57..6959cf0ba3 100644 --- a/tee-worker/core/tls-websocket-server/src/connection.rs +++ b/tee-worker/core/tls-websocket-server/src/connection.rs @@ -27,7 +27,7 @@ use log::*; use mio::{event::Event, net::TcpStream, Poll, Ready, Token}; use rustls::{ServerSession, Session}; use std::{ - format, + format, io, string::{String, ToString}, sync::Arc, time::Instant, @@ -146,14 +146,19 @@ where self.connection_token.0, e ); }, - Err(e) => match e { - tungstenite::Error::ConnectionClosed => return Ok(true), - tungstenite::Error::AlreadyClosed => return Ok(true), - _ => error!( - "Failed to read message from web-socket (connection {}): {:?}", - self.connection_token.0, e - ), - }, + Err(e) => + return match e { + tungstenite::Error::Io(e) if e.kind() == io::ErrorKind::WouldBlock => + Ok(false), + _ => { + trace!( + "Error while reading web-socket message (connection {}): {:?}", + self.connection_token.0, + e + ); + Ok(true) + }, + }, } trace!("Read successful for connection {}", self.connection_token.0); } else { diff --git a/tee-worker/docker/docker-compose.yml b/tee-worker/docker/docker-compose.yml index cc6beb8256..8bd55a0958 100644 --- a/tee-worker/docker/docker-compose.yml +++ b/tee-worker/docker/docker-compose.yml @@ -138,6 +138,7 @@ services: - KARAT_DAO_API_URL=http://localhost:19527/karat_dao/ - MAGIC_CRAFT_API_URL=http://localhost:19527/magic_craft/ - MAGIC_CRAFT_API_KEY= + - DAREN_MARKET_API_URL=http://localhost:19527/daren_market/ - MORALIS_API_KEY= - NODEREAL_API_KEY=NODEREAL_API_KEY - NODEREAL_API_URL=http://localhost:19527 diff --git a/tee-worker/docker/lit-assertion-contracts-test.yml b/tee-worker/docker/lit-assertion-contracts-test.yml new file mode 100644 index 0000000000..852311cffa --- /dev/null +++ b/tee-worker/docker/lit-assertion-contracts-test.yml @@ -0,0 +1,26 @@ +services: + lit-assertion-contracts-test: + image: litentry/identity-cli:latest + container_name: lit-assertion-contracts-test + volumes: + - ../ts-tests:/ts-tests + - ../client-api:/client-api + - ../cli:/usr/local/worker-cli + - ../litentry/core/assertion-build/src/dynamic/contracts:/assertion-contracts + + build: + context: .. + dockerfile: build.Dockerfile + target: deployed-client + depends_on: + litentry-node: + condition: service_healthy + litentry-worker-1: + condition: service_healthy + networks: + - litentry-test-network + entrypoint: "bash -c '/usr/local/worker-cli/lit_ts_integration_test.sh assertion_contracts.test.ts 2>&1' " + restart: "no" +networks: + litentry-test-network: + driver: bridge diff --git a/tee-worker/docker/lit-scheduled-enclave-multiworker-test.yml b/tee-worker/docker/lit-scheduled-enclave-multiworker-test.yml deleted file mode 100644 index d9465d1b10..0000000000 --- a/tee-worker/docker/lit-scheduled-enclave-multiworker-test.yml +++ /dev/null @@ -1,28 +0,0 @@ -services: - lit-scheduled-enclave-multiworker-test: - image: litentry/identity-cli:latest - container_name: litentry-scheduled-enclave-multiworker-test - volumes: - - ../ts-tests:/ts-tests - - ../client-api:/client-api - - ../cli:/usr/local/worker-cli - build: - context: .. - dockerfile: build.Dockerfile - target: deployed-client - depends_on: - litentry-node: - condition: service_healthy - litentry-worker-1: - condition: service_healthy - litentry-worker-2: - condition: service_healthy - litentry-worker-3: - condition: service_healthy - networks: - - litentry-test-network - entrypoint: "bash -c '/usr/local/worker-cli/lit_ts_integration_test.sh scheduled_enclave.test.ts 2>&1' " - restart: "no" -networks: - litentry-test-network: - driver: bridge diff --git a/tee-worker/docker/lit-scheduled-enclave-test.yml b/tee-worker/docker/lit-scheduled-enclave-test.yml deleted file mode 100644 index cfe93d749e..0000000000 --- a/tee-worker/docker/lit-scheduled-enclave-test.yml +++ /dev/null @@ -1,24 +0,0 @@ -services: - lit-scheduled-enclave-test: - image: litentry/identity-cli:latest - container_name: litentry-scheduled-enclave-test - volumes: - - ../ts-tests:/ts-tests - - ../client-api:/client-api - - ../cli:/usr/local/worker-cli - build: - context: .. - dockerfile: build.Dockerfile - target: deployed-client - depends_on: - litentry-node: - condition: service_healthy - litentry-worker-1: - condition: service_healthy - networks: - - litentry-test-network - entrypoint: "bash -c '/usr/local/worker-cli/lit_ts_integration_test.sh scheduled_enclave.test.ts 2>&1' " - restart: "no" -networks: - litentry-test-network: - driver: bridge diff --git a/tee-worker/docker/multiworker-docker-compose.yml b/tee-worker/docker/multiworker-docker-compose.yml index f5d94c5a2c..7cf162d91a 100644 --- a/tee-worker/docker/multiworker-docker-compose.yml +++ b/tee-worker/docker/multiworker-docker-compose.yml @@ -139,6 +139,7 @@ services: - KARAT_DAO_API_URL=http://localhost:19527/karat_dao/ - MAGIC_CRAFT_API_URL=http://localhost:19527/magic_craft/ - MAGIC_CRAFT_API_KEY= + - DAREN_MARKET_API_URL=http://localhost:19527/daren_market/ - MORALIS_API_KEY= - NODEREAL_API_KEY=NODEREAL_API_KEY - NODEREAL_API_URL=http://localhost:19527 @@ -203,6 +204,7 @@ services: - KARAT_DAO_API_URL=http://localhost:19527/karat_dao/ - MAGIC_CRAFT_API_URL=http://localhost:19527/magic_craft/ - MAGIC_CRAFT_API_KEY= + - DAREN_MARKET_API_URL=http://localhost:19527/daren_market/ - MORALIS_API_KEY= - NODEREAL_API_KEY=NODEREAL_API_KEY - NODEREAL_API_URL=http://localhost:19527 @@ -267,6 +269,7 @@ services: - KARAT_DAO_API_URL=http://localhost:19527/karat_dao/ - MAGIC_CRAFT_API_URL=http://localhost:19527/magic_craft/ - MAGIC_CRAFT_API_KEY= + - DAREN_MARKET_API_URL=http://localhost:19527/daren_market/ - MORALIS_API_KEY= - NODEREAL_API_KEY=NODEREAL_API_KEY - NODEREAL_API_URL=http://localhost:19527 diff --git a/tee-worker/enclave-runtime/Cargo.lock b/tee-worker/enclave-runtime/Cargo.lock index ec92a78860..3aeff4edd5 100644 --- a/tee-worker/enclave-runtime/Cargo.lock +++ b/tee-worker/enclave-runtime/Cargo.lock @@ -937,7 +937,6 @@ dependencies = [ "lc-evm-dynamic-assertions", "lc-identity-verification", "lc-parachain-extrinsic-task-receiver", - "lc-scheduled-enclave", "lc-stf-task-receiver", "lc-vc-task-receiver", "litentry-hex-utils", @@ -1986,7 +1985,7 @@ dependencies = [ "itp-utils", "lc-dynamic-assertion", "lc-evm-dynamic-assertions", - "lc-scheduled-enclave", + "lc-vc-task-sender", "litentry-hex-utils", "litentry-primitives", "log", @@ -2179,7 +2178,6 @@ dependencies = [ "itp-top-pool-author", "itp-types", "itp-utils", - "lc-scheduled-enclave", "litentry-primitives", "log", "parity-scale-codec", @@ -2815,7 +2813,6 @@ dependencies = [ "its-primitives", "its-state", "its-validateer-fetch", - "lc-scheduled-enclave", "litentry-hex-utils", "log", "parity-scale-codec", @@ -2868,7 +2865,6 @@ dependencies = [ "its-primitives", "its-state", "lazy_static", - "lc-scheduled-enclave", "log", "parity-scale-codec", "sgx_tstd", @@ -3150,6 +3146,7 @@ version = "0.1.0" dependencies = [ "base58", "blake2-rfc", + "chrono 0.4.11", "ethabi", "evm 0.41.1", "hex", @@ -3220,21 +3217,6 @@ dependencies = [ "sp-runtime", ] -[[package]] -name = "lc-scheduled-enclave" -version = "0.8.0" -dependencies = [ - "itp-settings", - "itp-sgx-io", - "itp-types", - "lazy_static", - "log", - "parity-scale-codec", - "sgx_tstd", - "sp-std", - "thiserror", -] - [[package]] name = "lc-service" version = "0.1.0" diff --git a/tee-worker/enclave-runtime/Cargo.toml b/tee-worker/enclave-runtime/Cargo.toml index d3e77fb40a..4ab85d5dfc 100644 --- a/tee-worker/enclave-runtime/Cargo.toml +++ b/tee-worker/enclave-runtime/Cargo.toml @@ -147,7 +147,6 @@ lc-data-providers = { path = "../litentry/core/data-providers", default-features lc-evm-dynamic-assertions = { path = "../litentry/core/evm-dynamic-assertions", default-features = false, features = ["sgx"] } lc-identity-verification = { path = "../litentry/core/identity-verification", default-features = false, features = ["sgx"] } lc-parachain-extrinsic-task-receiver = { path = "../litentry/core/parachain-extrinsic-task/receiver", default-features = false, features = ["sgx"] } -lc-scheduled-enclave = { path = "../litentry/core/scheduled-enclave", default-features = false, features = ["sgx"] } lc-stf-task-receiver = { path = "../litentry/core/stf-task/receiver", default-features = false, features = ["sgx"] } lc-vc-task-receiver = { path = "../litentry/core/vc-task/receiver", default-features = false, features = ["sgx"] } litentry-hex-utils = { path = "../../primitives/hex", default-features = false } diff --git a/tee-worker/enclave-runtime/Enclave.edl b/tee-worker/enclave-runtime/Enclave.edl index 24cd416f61..2f46e3d538 100644 --- a/tee-worker/enclave-runtime/Enclave.edl +++ b/tee-worker/enclave-runtime/Enclave.edl @@ -171,11 +171,10 @@ enclave { public size_t test_main_entrance(); public sgx_status_t migrate_shard( - [in, size=shard_size] uint8_t* old_shard, - [in, size=shard_size] uint8_t* new_shard, + [in, size=shard_size] uint8_t* new_shard, uint32_t shard_size ); - + public sgx_status_t ignore_parentchain_block_import_validation_until( [in] uint32_t* until ); diff --git a/tee-worker/enclave-runtime/src/attestation.rs b/tee-worker/enclave-runtime/src/attestation.rs index 71c7346853..37621636a7 100644 --- a/tee-worker/enclave-runtime/src/attestation.rs +++ b/tee-worker/enclave-runtime/src/attestation.rs @@ -54,7 +54,7 @@ use itp_settings::{ use itp_sgx_crypto::{ ed25519_derivation::DeriveEd25519, key_repository::AccessKey, Error as SgxCryptoError, }; -use itp_types::{AttestationType, OpaqueCall, WorkerType}; +use itp_types::{AttestationType, DcapProvider, OpaqueCall, WorkerType}; use itp_utils::write_slice_and_whitespace_pad; use log::*; use sgx_types::*; @@ -330,7 +330,7 @@ pub fn generate_dcap_ra_extrinsic_from_quote_internal( let shielding_pubkey = get_shielding_pubkey()?; let vc_pubkey = get_vc_pubkey()?; - let attestation_type = AttestationType::Dcap(Default::default()); // skip_ra should be false here already + let attestation_type = AttestationType::Dcap(DcapProvider::Intel); // skip_ra should be false here already let call = OpaqueCall::from_tuple(&( call_ids, diff --git a/tee-worker/enclave-runtime/src/initialization/global_components.rs b/tee-worker/enclave-runtime/src/initialization/global_components.rs index a6ff5e0142..84c335789d 100644 --- a/tee-worker/enclave-runtime/src/initialization/global_components.rs +++ b/tee-worker/enclave-runtime/src/initialization/global_components.rs @@ -93,7 +93,6 @@ use its_sidechain::{ use lazy_static::lazy_static; use lc_data_providers::DataProviderConfig; use lc_evm_dynamic_assertions::{repository::EvmAssertionRepository, sealing::io::AssertionsSeal}; -use lc_scheduled_enclave::ScheduledEnclaveSeal as EnclaveScheduledEnclaveSeal; use litentry_primitives::BroadcastedRequest; use sgx_crypto_helper::rsa3072::Rsa3072KeyPair; use sgx_tstd::vec::Vec; @@ -351,7 +350,6 @@ pub type EnclaveSealHandler = SealHandler< EnclaveStateKeyRepository, EnclaveStateHandler, EnclaveLightClientSeal, - EnclaveScheduledEnclaveSeal, AssertionsSeal, >; pub type EnclaveOffchainWorkerExecutor = itc_offchain_worker_executor::executor::Executor< diff --git a/tee-worker/enclave-runtime/src/initialization/mod.rs b/tee-worker/enclave-runtime/src/initialization/mod.rs index 91e842370e..d368f5b407 100644 --- a/tee-worker/enclave-runtime/src/initialization/mod.rs +++ b/tee-worker/enclave-runtime/src/initialization/mod.rs @@ -63,7 +63,7 @@ use itc_tls_websocket_server::{ config_provider::FromFileConfigProvider, ws_server::TungsteniteWsServer, ConnectionToken, WebSocketServer, }; -use itp_attestation_handler::{AttestationHandler, IntelAttestationHandler}; +use itp_attestation_handler::IntelAttestationHandler; use itp_component_container::{ComponentGetter, ComponentInitializer}; use itp_primitives_cache::GLOBAL_PRIMITIVES_CACHE; use itp_settings::files::{ @@ -88,7 +88,6 @@ use its_sidechain::{ use lc_data_providers::DataProviderConfig; use lc_evm_dynamic_assertions::repository::EvmAssertionRepository; use lc_parachain_extrinsic_task_receiver::run_parachain_extrinsic_task_receiver; -use lc_scheduled_enclave::{ScheduledEnclaveUpdater, GLOBAL_SCHEDULED_ENCLAVE}; use lc_stf_task_receiver::{run_stf_task_receiver, StfTaskContext}; use lc_vc_task_receiver::run_vc_handler_runner; use litentry_primitives::BroadcastedRequest; @@ -215,6 +214,7 @@ pub(crate) fn init_enclave( top_pool_author, getter_executor, shielding_key_repository, + ocall_api.clone(), Some(state_handler), data_provider_config, ); @@ -336,11 +336,6 @@ pub(crate) fn init_enclave_sidechain_components( let top_pool_author = GLOBAL_TOP_POOL_AUTHOR_COMPONENT.get()?; let state_key_repository = GLOBAL_STATE_KEY_REPOSITORY_COMPONENT.get()?; - // GLOBAL_SCHEDULED_ENCLAVE must be initialized after attestation_handler and enclave - let attestation_handler = GLOBAL_ATTESTATION_HANDLER_COMPONENT.get()?; - let mrenclave = attestation_handler.get_mrenclave()?; - GLOBAL_SCHEDULED_ENCLAVE.init(mrenclave).map_err(|e| Error::Other(e.into()))?; - let parentchain_block_import_dispatcher = get_triggered_dispatcher_from_integritee_solo_or_parachain()?; @@ -457,12 +452,9 @@ pub(crate) fn init_shard(shard: ShardIdentifier) -> EnclaveResult<()> { Ok(()) } -pub(crate) fn migrate_shard( - old_shard: ShardIdentifier, - new_shard: ShardIdentifier, -) -> EnclaveResult<()> { +pub(crate) fn migrate_shard(new_shard: ShardIdentifier) -> EnclaveResult<()> { let state_handler = GLOBAL_STATE_HANDLER_COMPONENT.get()?; - let _ = state_handler.migrate_shard(old_shard, new_shard)?; + let _ = state_handler.migrate_shard(new_shard)?; Ok(()) } diff --git a/tee-worker/enclave-runtime/src/lib.rs b/tee-worker/enclave-runtime/src/lib.rs index 93f77a8f37..77dc952a22 100644 --- a/tee-worker/enclave-runtime/src/lib.rs +++ b/tee-worker/enclave-runtime/src/lib.rs @@ -478,19 +478,12 @@ pub unsafe extern "C" fn init_shard(shard: *const u8, shard_size: u32) -> sgx_st } #[no_mangle] -pub unsafe extern "C" fn migrate_shard( - old_shard: *const u8, - new_shard: *const u8, - shard_size: u32, -) -> sgx_status_t { - let old_shard_identifier = - ShardIdentifier::from_slice(slice::from_raw_parts(old_shard, shard_size as usize)); - - let new_shard_identifier = +pub unsafe extern "C" fn migrate_shard(new_shard: *const u8, shard_size: u32) -> sgx_status_t { + let shard_identifier = ShardIdentifier::from_slice(slice::from_raw_parts(new_shard, shard_size as usize)); - if let Err(e) = initialization::migrate_shard(old_shard_identifier, new_shard_identifier) { - error!("Failed to initialize shard ({:?}): {:?}", old_shard_identifier, e); + if let Err(e) = initialization::migrate_shard(shard_identifier) { + error!("Failed to migrate shard ({:?}): {:?}", shard_identifier, e); return sgx_status_t::SGX_ERROR_UNEXPECTED } diff --git a/tee-worker/enclave-runtime/src/rpc/worker_api_direct.rs b/tee-worker/enclave-runtime/src/rpc/worker_api_direct.rs index bd611ef157..d227d4b1d1 100644 --- a/tee-worker/enclave-runtime/src/rpc/worker_api_direct.rs +++ b/tee-worker/enclave-runtime/src/rpc/worker_api_direct.rs @@ -27,6 +27,7 @@ use core::result::Result; use ita_sgx_runtime::{Runtime, System}; use ita_stf::{aes_encrypt_default, AesOutput, Getter, TrustedCallSigned}; use itc_parentchain::light_client::{concurrent_access::ValidatorAccess, ExtrinsicSender}; +use itp_ocall_api::EnclaveAttestationOCallApi; use itp_primitives_cache::{GetPrimitives, GLOBAL_PRIMITIVES_CACHE}; use itp_rpc::RpcReturnValue; use itp_sgx_crypto::{ @@ -47,7 +48,6 @@ use its_sidechain::rpc_handler::{ use jsonrpc_core::{serde_json::json, IoHandler, Params, Value}; use lc_data_providers::DataProviderConfig; use lc_identity_verification::web2::twitter; -use lc_scheduled_enclave::{ScheduledEnclaveUpdater, GLOBAL_SCHEDULED_ENCLAVE}; use litentry_macros::{if_development, if_development_or}; use litentry_primitives::{aes_decrypt, AesRequest, DecryptableRequest, Identity}; use log::debug; @@ -70,10 +70,11 @@ fn get_all_rpc_methods_string(io_handler: &IoHandler) -> String { format!("methods: [{}]", method_string) } -pub fn public_api_rpc_handler( +pub fn public_api_rpc_handler( top_pool_author: Arc, getter_executor: Arc, shielding_key: Arc, + ocall_api: Arc, state: Option>, data_provider_config: Arc, ) -> IoHandler @@ -83,6 +84,7 @@ where AccessShieldingKey: AccessPubkey + AccessKey + Send + Sync + 'static, ::KeyType: ShieldingCryptoDecrypt + ShieldingCryptoEncrypt + DeriveEd25519 + Send + Sync + 'static, + OcallApi: EnclaveAttestationOCallApi + Send + Sync + 'static, State: HandleState + Send + Sync + 'static, State::StateT: SgxExternalitiesTrait, { @@ -356,17 +358,16 @@ where }); // state_getMrenclave - io.add_sync_method("state_getMrenclave", |_: Params| { - let json_value = match GLOBAL_SCHEDULED_ENCLAVE.get_current_mrenclave() { - Ok(mrenclave) => RpcReturnValue { + io.add_sync_method("state_getMrenclave", move |_: Params| { + let json_value = match ocall_api.get_mrenclave_of_self() { + Ok(m) => RpcReturnValue { do_watch: false, - value: mrenclave.encode(), + value: m.m.encode(), status: DirectRequestStatus::Ok, } .to_hex(), - Err(error) => { - let error_msg: String = - format!("Could not get current mrenclave due to: {}", error); + Err(e) => { + let error_msg: String = format!("Could not get current mrenclave due to: {}", e); compute_hex_encoded_return_error(error_msg.as_str()) }, }; @@ -374,44 +375,6 @@ where }); if_development!({ - use itp_types::{MrEnclave, SidechainBlockNumber}; - // state_setScheduledEnclave, params: sidechainBlockNumber, hex encoded mrenclave - io.add_sync_method("state_setScheduledEnclave", move |params: Params| { - match params.parse::<(SidechainBlockNumber, String)>() { - Ok((bn, mrenclave)) => - return match hex::decode(&mrenclave) { - Ok(mrenclave) => { - let mut enclave_to_set: MrEnclave = [0u8; 32]; - if mrenclave.len() != enclave_to_set.len() { - return Ok(json!(compute_hex_encoded_return_error( - "mrenclave len mismatch, expected 32 bytes long" - ))) - } - - enclave_to_set.copy_from_slice(&mrenclave); - return match GLOBAL_SCHEDULED_ENCLAVE.update(bn, enclave_to_set) { - Ok(()) => Ok(json!(RpcReturnValue::new( - vec![], - false, - DirectRequestStatus::Ok - ) - .to_hex())), - Err(e) => { - let error_msg = - format!("Failed to set scheduled mrenclave {:?}", e); - Ok(json!(compute_hex_encoded_return_error(error_msg.as_str()))) - }, - } - }, - Err(e) => { - let error_msg = format!("Failed to decode mrenclave {:?}", e); - Ok(json!(compute_hex_encoded_return_error(error_msg.as_str()))) - }, - }, - Err(_) => Ok(json!(compute_hex_encoded_return_error("parse error"))), - } - }); - // state_getStorage io.add_sync_method("state_getStorage", move |params: Params| { let local_state = match state.clone() { @@ -463,22 +426,6 @@ where }); }); - io.add_sync_method("state_getScheduledEnclave", move |_: Params| { - debug!("worker_api_direct rpc was called: state_getScheduledEnclave"); - let json_value = match GLOBAL_SCHEDULED_ENCLAVE.registry.read() { - Ok(registry) => { - let mut serialized_registry = vec![]; - for (block_number, mrenclave) in registry.iter() { - serialized_registry.push((*block_number, *mrenclave)); - } - RpcReturnValue::new(serialized_registry.encode(), false, DirectRequestStatus::Ok) - .to_hex() - }, - Err(_err) => compute_hex_encoded_return_error("Poisoned registry storage"), - }; - Ok(json!(json_value)) - }); - // system_health io.add_sync_method("system_health", |_: Params| { debug!("worker_api_direct rpc was called: system_health"); diff --git a/tee-worker/enclave-runtime/src/test/direct_rpc_tests.rs b/tee-worker/enclave-runtime/src/test/direct_rpc_tests.rs index 417cfac1e6..885d987bcf 100644 --- a/tee-worker/enclave-runtime/src/test/direct_rpc_tests.rs +++ b/tee-worker/enclave-runtime/src/test/direct_rpc_tests.rs @@ -16,7 +16,9 @@ */ -use crate::{rpc::worker_api_direct::public_api_rpc_handler, Hash}; +use crate::{ + rpc::worker_api_direct::public_api_rpc_handler, test::mocks::types::TestOCallApi, Hash, +}; use codec::{Decode, Encode}; use ita_stf::{Getter, PublicGetter}; use itc_direct_rpc_server::{ @@ -46,6 +48,8 @@ pub fn get_state_request_works() { let watch_extractor = Arc::new(create_determine_watch::()); let rsa_repository = get_rsa3072_repository(temp_dir.path().to_path_buf()).unwrap(); + let ocall_api = TestOCallApi::default().with_mr_enclave([1u8; 32]); + let state: TestState = 78234u64; let state_observer = Arc::new(ObserveStateMock::::new(state)); let getter_executor = @@ -58,6 +62,7 @@ pub fn get_state_request_works() { top_pool_author, getter_executor, Arc::new(rsa_repository), + ocall_api.into(), None::>, Arc::new(data_provider_config), ); diff --git a/tee-worker/enclave-runtime/src/test/sidechain_aura_tests.rs b/tee-worker/enclave-runtime/src/test/sidechain_aura_tests.rs index 36ad0f69b9..0e2c6639c9 100644 --- a/tee-worker/enclave-runtime/src/test/sidechain_aura_tests.rs +++ b/tee-worker/enclave-runtime/src/test/sidechain_aura_tests.rs @@ -60,7 +60,6 @@ use its_block_verification::slot::slot_from_timestamp_and_duration; use its_primitives::{traits::Block, types::SignedBlock as SignedSidechainBlock}; use its_sidechain::{aura::proposer_factory::ProposerFactory, slots::SlotInfo}; use jsonrpc_core::futures::executor; -use lc_scheduled_enclave::ScheduledEnclaveMock; use litentry_primitives::Identity; use log::*; use primitive_types::H256; @@ -188,11 +187,10 @@ pub fn produce_sidechain_block_and_import_it() { info!("Test setup is done."); let state_hash_before_block_production = get_state_hash(state_handler.as_ref(), &shard_id); - let scheduled_enclave = Arc::new(ScheduledEnclaveMock::default()); info!("Executing AURA on slot.."); let (blocks, opaque_calls) = - exec_aura_on_slot::<_, ParentchainBlock, SignedSidechainBlock, _, _, _, _, _, _, _>( + exec_aura_on_slot::<_, ParentchainBlock, SignedSidechainBlock, _, _, _, _, _>( slot_info, signer, ocall_api, @@ -201,8 +199,6 @@ pub fn produce_sidechain_block_and_import_it() { None::>, proposer_environment, shards, - scheduled_enclave, - state_handler.clone(), ) .unwrap(); diff --git a/tee-worker/enclave-runtime/src/test/sidechain_event_tests.rs b/tee-worker/enclave-runtime/src/test/sidechain_event_tests.rs index 64294f0121..458ea2053b 100644 --- a/tee-worker/enclave-runtime/src/test/sidechain_event_tests.rs +++ b/tee-worker/enclave-runtime/src/test/sidechain_event_tests.rs @@ -48,7 +48,6 @@ use itp_types::Block as ParentchainBlock; use its_block_verification::slot::slot_from_timestamp_and_duration; use its_primitives::types::SignedBlock as SignedSidechainBlock; use its_sidechain::{aura::proposer_factory::ProposerFactory, slots::SlotInfo}; -use lc_scheduled_enclave::ScheduledEnclaveMock; use log::*; use primitive_types::H256; use sgx_crypto_helper::RsaKeyPair; @@ -154,10 +153,9 @@ pub fn ensure_events_get_reset_upon_block_proposal() { None, ); - let scheduled_enclave = Arc::new(ScheduledEnclaveMock::default()); info!("Executing AURA on slot.."); let (blocks, opaque_calls) = - exec_aura_on_slot::<_, ParentchainBlock, SignedSidechainBlock, _, _, _, _, _, _, _>( + exec_aura_on_slot::<_, ParentchainBlock, SignedSidechainBlock, _, _, _, _, _>( slot_info, signer, ocall_api, @@ -166,8 +164,6 @@ pub fn ensure_events_get_reset_upon_block_proposal() { None::>, proposer_environment, shards, - scheduled_enclave, - state_handler.clone(), ) .unwrap(); diff --git a/tee-worker/enclave-runtime/src/tls_ra/mocks.rs b/tee-worker/enclave-runtime/src/tls_ra/mocks.rs index a8420174d5..65c3386baf 100644 --- a/tee-worker/enclave-runtime/src/tls_ra/mocks.rs +++ b/tee-worker/enclave-runtime/src/tls_ra/mocks.rs @@ -29,7 +29,6 @@ pub struct SealHandlerMock { pub state_key: Arc>>, pub state: Arc>>, pub light_client_state: Arc>>, - pub scheduled_enclave_state: Arc>>, pub assertions_state: Arc>>, } @@ -39,17 +38,9 @@ impl SealHandlerMock { state_key: Arc>>, state: Arc>>, light_client_state: Arc>>, - scheduled_enclave_state: Arc>>, assertions_state: Arc>>, ) -> Self { - Self { - shielding_key, - state_key, - state, - light_client_state, - scheduled_enclave_state, - assertions_state, - } + Self { shielding_key, state_key, state, light_client_state, assertions_state } } } @@ -78,11 +69,6 @@ impl SealStateAndKeys for SealHandlerMock { Ok(()) } - fn seal_scheduled_enclave_state(&self, bytes: &[u8]) -> EnclaveResult<()> { - *self.scheduled_enclave_state.write().unwrap() = bytes.to_vec(); - Ok(()) - } - fn seal_assertions_state(&self, bytes: &[u8]) -> EnclaveResult<()> { *self.assertions_state.write().unwrap() = bytes.to_vec(); Ok(()) @@ -106,10 +92,6 @@ impl UnsealStateAndKeys for SealHandlerMock { Ok(self.light_client_state.read().unwrap().clone()) } - fn unseal_scheduled_enclave_state(&self) -> EnclaveResult> { - Ok(self.scheduled_enclave_state.read().unwrap().clone()) - } - fn unseal_assertions_state(&self) -> EnclaveResult> { Ok(self.assertions_state.read().unwrap().clone()) } diff --git a/tee-worker/enclave-runtime/src/tls_ra/mod.rs b/tee-worker/enclave-runtime/src/tls_ra/mod.rs index 392577d1fc..44ff02bced 100644 --- a/tee-worker/enclave-runtime/src/tls_ra/mod.rs +++ b/tee-worker/enclave-runtime/src/tls_ra/mod.rs @@ -53,7 +53,6 @@ pub enum Opcode { StateKey, State, LightClient, - ScheduledEnclave, Assertions, } @@ -64,8 +63,7 @@ impl From for Opcode { 1 => Opcode::StateKey, 2 => Opcode::State, 3 => Opcode::LightClient, - 4 => Opcode::ScheduledEnclave, - 5 => Opcode::Assertions, + 4 => Opcode::Assertions, _ => unimplemented!("Unsupported/unknown Opcode for MU-RA exchange"), } } diff --git a/tee-worker/enclave-runtime/src/tls_ra/seal_handler.rs b/tee-worker/enclave-runtime/src/tls_ra/seal_handler.rs index 966b963234..bc7d119eb0 100644 --- a/tee-worker/enclave-runtime/src/tls_ra/seal_handler.rs +++ b/tee-worker/enclave-runtime/src/tls_ra/seal_handler.rs @@ -31,7 +31,6 @@ use itp_sgx_io::SealedIO; use itp_stf_state_handler::handle_state::HandleState; use itp_types::ShardIdentifier; use lc_evm_dynamic_assertions::sealing::UnsealedAssertions; -use lc_scheduled_enclave::ScheduledEnclaveMap; use log::*; use sgx_crypto_helper::rsa3072::Rsa3072KeyPair; use std::{sync::Arc, vec::Vec}; @@ -43,31 +42,21 @@ pub struct SealHandler< StateKeyRepository, StateHandler, LightClientSeal, - ScheduledEnclaveSeal, AssertionsSeal, > { state_handler: Arc, state_key_repository: Arc, shielding_key_repository: Arc, light_client_seal: Arc, - scheduled_enclave_seal: Arc, assertions_seal: Arc, } -impl< - ShieldingKeyRepository, - StateKeyRepository, - StateHandler, - LightClientSeal, - ScheduledEnclaveSeal, - AssertionsSeal, - > +impl SealHandler< ShieldingKeyRepository, StateKeyRepository, StateHandler, LightClientSeal, - ScheduledEnclaveSeal, AssertionsSeal, > { @@ -76,7 +65,6 @@ impl< state_key_repository: Arc, shielding_key_repository: Arc, light_client_seal: Arc, - scheduled_enclave_seal: Arc, assertions_seal: Arc, ) -> Self { Self { @@ -84,7 +72,6 @@ impl< state_key_repository, shielding_key_repository, light_client_seal, - scheduled_enclave_seal, assertions_seal, } } @@ -96,7 +83,6 @@ pub trait SealStateAndKeys { fn seal_state(&self, bytes: &[u8], shard: &ShardIdentifier) -> EnclaveResult<()>; fn seal_new_empty_state(&self, shard: &ShardIdentifier) -> EnclaveResult<()>; fn seal_light_client_state(&self, bytes: &[u8]) -> EnclaveResult<()>; - fn seal_scheduled_enclave_state(&self, bytes: &[u8]) -> EnclaveResult<()>; fn seal_assertions_state(&self, bytes: &[u8]) -> EnclaveResult<()>; } @@ -105,24 +91,16 @@ pub trait UnsealStateAndKeys { fn unseal_state_key(&self) -> EnclaveResult>; fn unseal_state(&self, shard: &ShardIdentifier) -> EnclaveResult>; fn unseal_light_client_state(&self) -> EnclaveResult>; - fn unseal_scheduled_enclave_state(&self) -> EnclaveResult>; fn unseal_assertions_state(&self) -> EnclaveResult>; } -impl< - ShieldingKeyRepository, - StateKeyRepository, - StateHandler, - LightClientSeal, - ScheduledEnclaveSeal, - AssertionsSeal, - > SealStateAndKeys +impl + SealStateAndKeys for SealHandler< ShieldingKeyRepository, StateKeyRepository, StateHandler, LightClientSeal, - ScheduledEnclaveSeal, AssertionsSeal, > where ShieldingKeyRepository: AccessKey + MutateKey, @@ -130,7 +108,6 @@ impl< StateHandler: HandleState, LightClientSeal: LightClientSealing, LightClientSeal::LightClientState: Decode, - ScheduledEnclaveSeal: SealedIO, AssertionsSeal: SealedIO, { fn seal_shielding_key(&self, bytes: &[u8]) -> EnclaveResult<()> { @@ -166,16 +143,6 @@ impl< Ok(()) } - fn seal_scheduled_enclave_state(&self, mut bytes: &[u8]) -> EnclaveResult<()> { - let state: ::Unsealed = Decode::decode(&mut bytes)?; - self.scheduled_enclave_seal.seal(&state).map_err(|e| { - error!(" [Enclave] Failed to seal scheduled enclave: {:?}", e); - EnclaveError::Other(format!("{:?}", e).into()) - })?; - info!("Successfully sealed scheduled enclave"); - Ok(()) - } - fn seal_assertions_state(&self, mut bytes: &[u8]) -> EnclaveResult<()> { let state: ::Unsealed = Decode::decode(&mut bytes)?; self.assertions_seal.seal(&state).map_err(|e| { @@ -200,20 +167,13 @@ impl< } } -impl< - ShieldingKeyRepository, - StateKeyRepository, - StateHandler, - LightClientSeal, - ScheduledEnclaveSeal, - AssertionsSeal, - > UnsealStateAndKeys +impl + UnsealStateAndKeys for SealHandler< ShieldingKeyRepository, StateKeyRepository, StateHandler, LightClientSeal, - ScheduledEnclaveSeal, AssertionsSeal, > where ShieldingKeyRepository: AccessKey + MutateKey, @@ -221,7 +181,6 @@ impl< StateHandler: HandleState, LightClientSeal: LightClientSealing, LightClientSeal::LightClientState: Encode, - ScheduledEnclaveSeal: SealedIO, AssertionsSeal: SealedIO, { fn unseal_shielding_key(&self) -> EnclaveResult> { @@ -247,14 +206,6 @@ impl< Ok(self.light_client_seal.unseal()?.encode()) } - fn unseal_scheduled_enclave_state(&self) -> EnclaveResult> { - let scheduled_enclave = self.scheduled_enclave_seal.unseal().map_err(|e| { - error!(" [Enclave] Failed to unseal scheduled enclave: {:?}", e); - EnclaveError::Other(format!("{:?}", e).into()) - })?; - Ok(Encode::encode(&scheduled_enclave)) - } - fn unseal_assertions_state(&self) -> EnclaveResult> { let assertions = self.assertions_seal.unseal().map_err(|e| { error!(" [Enclave] Failed to unseal assertions: {:?}", e); @@ -272,7 +223,6 @@ pub mod test { use itp_sgx_crypto::mocks::KeyRepositoryMock; use itp_test::mock::handle_state_mock::HandleStateMock; use lc_evm_dynamic_assertions::mock::AssertionsSealMock; - use lc_scheduled_enclave::mock::ScheduledEnclaveSealMock; type StateKeyRepositoryMock = KeyRepositoryMock; type ShieldingKeyRepositoryMock = KeyRepositoryMock; @@ -282,7 +232,6 @@ pub mod test { StateKeyRepositoryMock, HandleStateMock, LightValidationStateSealMock, - ScheduledEnclaveSealMock, AssertionsSealMock, >; diff --git a/tee-worker/enclave-runtime/src/tls_ra/tests.rs b/tee-worker/enclave-runtime/src/tls_ra/tests.rs index 5b5596d086..44fe6728b8 100644 --- a/tee-worker/enclave-runtime/src/tls_ra/tests.rs +++ b/tee-worker/enclave-runtime/src/tls_ra/tests.rs @@ -35,7 +35,6 @@ use itp_stf_state_handler::handle_state::HandleState; use itp_test::mock::handle_state_mock::HandleStateMock; use itp_types::ShardIdentifier; use lc_evm_dynamic_assertions::mock::AssertionsSealMock; -use lc_scheduled_enclave::mock::ScheduledEnclaveSealMock; use sgx_crypto_helper::{rsa3072::Rsa3072KeyPair, RsaKeyPair}; use sgx_types::{sgx_quote_sign_type_t, sgx_target_info_t}; use std::{ @@ -79,10 +78,6 @@ pub fn test_tls_ra_server_client_networking() { let state_key_encoded = vec![5, 2, 3, 7]; let state_encoded = Vec::from([1u8; 26000]); // Have a decently sized state, so read() must be called multiple times. let light_client_state_encoded = Vec::from([1u8; 10000]); // Have a decently sized state, so read() must be called multiple times. - let scheduled_enclave_state_encoded = vec![ - 4, 0, 0, 0, 0, 0, 0, 0, 0, 51, 162, 48, 234, 94, 231, 35, 92, 167, 183, 221, 185, 208, 147, - 215, 100, 27, 7, 66, 47, 78, 248, 110, 91, 83, 225, 121, 14, 125, 180, 231, 175, - ]; let assertions_state_encoded = vec![]; let server_seal_handler = SealHandlerMock::new( @@ -90,7 +85,6 @@ pub fn test_tls_ra_server_client_networking() { Arc::new(RwLock::new(state_key_encoded.clone())), Arc::new(RwLock::new(state_encoded.clone())), Arc::new(RwLock::new(light_client_state_encoded.clone())), - Arc::new(RwLock::new(scheduled_enclave_state_encoded.clone())), Arc::new(RwLock::new(assertions_state_encoded.clone())), ); let initial_client_state = vec![0, 0, 1]; @@ -100,7 +94,6 @@ pub fn test_tls_ra_server_client_networking() { let client_state_key = Arc::new(RwLock::new(initial_client_state_key.clone())); let client_state = Arc::new(RwLock::new(initial_client_state.clone())); let client_light_client_state = Arc::new(RwLock::new(initial_client_light_client_state)); - let scheduled_enclave_state = Arc::new(RwLock::new(Vec::new())); let assertions_state = Arc::new(RwLock::new(Vec::new())); let client_seal_handler = SealHandlerMock::new( @@ -108,7 +101,6 @@ pub fn test_tls_ra_server_client_networking() { client_state_key.clone(), client_state.clone(), client_light_client_state.clone(), - scheduled_enclave_state.clone(), assertions_state.clone(), ); @@ -200,7 +192,6 @@ fn create_seal_handler( let state_handler = Arc::new(HandleStateMock::default()); state_handler.reset(state, shard).unwrap(); let seal = Arc::new(LightValidationStateSealMock::new()); - let scheduled_enclave_seal = Arc::new(ScheduledEnclaveSealMock::new()); let assertions_seal = Arc::new(AssertionsSealMock::new()); SealHandler::new( @@ -208,7 +199,6 @@ fn create_seal_handler( state_key_repository, shielding_key_repository, seal, - scheduled_enclave_seal, assertions_seal, ) } diff --git a/tee-worker/enclave-runtime/src/tls_ra/tls_ra_client.rs b/tee-worker/enclave-runtime/src/tls_ra/tls_ra_client.rs index 7bdf55be94..7fba5d6062 100644 --- a/tee-worker/enclave-runtime/src/tls_ra/tls_ra_client.rs +++ b/tee-worker/enclave-runtime/src/tls_ra/tls_ra_client.rs @@ -31,8 +31,6 @@ use crate::{ }; use codec::Encode; -use lc_scheduled_enclave::{ScheduledEnclaveSeal, GLOBAL_SCHEDULED_ENCLAVE}; - use itp_attestation_handler::{RemoteAttestationType, DEV_HOSTNAME}; use itp_component_container::ComponentGetter; @@ -140,7 +138,6 @@ where Opcode::StateKey => self.seal_handler.seal_state_key(&bytes)?, Opcode::State => self.seal_handler.seal_state(&bytes, &self.shard)?, Opcode::LightClient => self.seal_handler.seal_light_client_state(&bytes)?, - Opcode::ScheduledEnclave => self.seal_handler.seal_scheduled_enclave_state(&bytes)?, Opcode::Assertions => self.seal_handler.seal_assertions_state(&bytes)?, }; Ok(Some(header.opcode)) @@ -216,9 +213,6 @@ pub unsafe extern "C" fn request_state_provisioning( }, }; - let scheduled_enclave_seal = - Arc::new(ScheduledEnclaveSeal::new(GLOBAL_SCHEDULED_ENCLAVE.seal_path.clone())); - let assertions_seal = Arc::new(AssertionsSeal::new(ASSERTIONS_FILE.into())); let seal_handler = EnclaveSealHandler::new( @@ -226,7 +220,6 @@ pub unsafe extern "C" fn request_state_provisioning( state_key_repository, shielding_key_repository, light_client_seal, - scheduled_enclave_seal, assertions_seal, ); diff --git a/tee-worker/enclave-runtime/src/tls_ra/tls_ra_server.rs b/tee-worker/enclave-runtime/src/tls_ra/tls_ra_server.rs index f8509064ae..0b01f7214e 100644 --- a/tee-worker/enclave-runtime/src/tls_ra/tls_ra_server.rs +++ b/tee-worker/enclave-runtime/src/tls_ra/tls_ra_server.rs @@ -36,7 +36,6 @@ use itp_ocall_api::EnclaveAttestationOCallApi; use itp_settings::worker_mode::{ProvideWorkerMode, WorkerMode, WorkerModeProvider}; use itp_types::ShardIdentifier; use lc_evm_dynamic_assertions::{sealing::io::AssertionsSeal, ASSERTIONS_FILE}; -use lc_scheduled_enclave::{ScheduledEnclaveSeal, GLOBAL_SCHEDULED_ENCLAVE}; use log::*; use rustls::{ServerConfig, ServerSession, StreamOwned}; use sgx_types::*; @@ -115,7 +114,6 @@ where self.write_state_key()?; self.write_state(shard)?; self.write_light_client_state()?; - self.write_scheduled_enclave_state()?; self.write_assertions_state()?; }, ProvisioningPayload::ShieldingKeyAndLightClient => { @@ -152,12 +150,6 @@ where Ok(()) } - fn write_scheduled_enclave_state(&mut self) -> EnclaveResult<()> { - let state = self.seal_handler.unseal_scheduled_enclave_state()?; - self.write(Opcode::ScheduledEnclave, &state)?; - Ok(()) - } - fn write_assertions_state(&mut self) -> EnclaveResult<()> { let state = self.seal_handler.unseal_assertions_state()?; self.write(Opcode::Assertions, &state)?; @@ -227,9 +219,6 @@ pub unsafe extern "C" fn run_state_provisioning_server( }, }; - let scheduled_enclave_seal = - Arc::new(ScheduledEnclaveSeal::new(GLOBAL_SCHEDULED_ENCLAVE.seal_path.clone())); - let assertions_seal = Arc::new(AssertionsSeal::new(ASSERTIONS_FILE.into())); let seal_handler = EnclaveSealHandler::new( @@ -237,7 +226,6 @@ pub unsafe extern "C" fn run_state_provisioning_server( state_key_repository, shielding_key_repository, light_client_seal, - scheduled_enclave_seal, assertions_seal, ); diff --git a/tee-worker/enclave-runtime/src/top_pool_execution.rs b/tee-worker/enclave-runtime/src/top_pool_execution.rs index 12a10e095d..bc1023758b 100644 --- a/tee-worker/enclave-runtime/src/top_pool_execution.rs +++ b/tee-worker/enclave-runtime/src/top_pool_execution.rs @@ -52,8 +52,7 @@ use itp_extrinsics_factory::CreateExtrinsics; use itp_ocall_api::{EnclaveMetricsOCallApi, EnclaveOnChainOCallApi, EnclaveSidechainOCallApi}; use itp_settings::sidechain::SLOT_DURATION; use itp_sgx_crypto::key_repository::AccessKey; -use itp_sgx_externalities::SgxExternalities; -use itp_stf_state_handler::{handle_state::HandleState, query_shard_state::QueryShardState}; +use itp_stf_state_handler::query_shard_state::QueryShardState; use itp_time_utils::duration_now; use itp_types::{parentchain::ParentchainCall, Block, OpaqueCall, H256}; use its_primitives::{ @@ -68,7 +67,6 @@ use its_sidechain::{ slots::{yield_next_slot, LastSlot, PerShardSlotWorkerScheduler, SlotInfo}, validateer_fetch::ValidateerFetch, }; -use lc_scheduled_enclave::{ScheduledEnclaveUpdater, GLOBAL_SCHEDULED_ENCLAVE}; use litentry_macros::if_development; use log::*; use sgx_types::sgx_status_t; @@ -210,7 +208,7 @@ fn execute_top_pool_trusted_calls_internal() -> Result<()> { }); let (blocks, parentchain_calls) = - exec_aura_on_slot::<_, _, SignedSidechainBlock, _, _, _, _, _, _, _>( + exec_aura_on_slot::<_, _, SignedSidechainBlock, _, _, _, _, _>( slot.clone(), authority, ocall_api.clone(), @@ -219,8 +217,6 @@ fn execute_top_pool_trusted_calls_internal() -> Result<()> { maybe_target_b_parentchain_import_dispatcher, env, shards, - GLOBAL_SCHEDULED_ENCLAVE.clone(), - state_handler, )?; if_development!({ @@ -263,8 +259,6 @@ pub(crate) fn exec_aura_on_slot< IntegriteeBlockImportTrigger, TargetABlockImportTrigger, TargetBBlockImportTrigger, - ScheduledEnclave, - StateHandler, >( slot: SlotInfo, authority: Authority, @@ -274,8 +268,6 @@ pub(crate) fn exec_aura_on_slot< maybe_target_b_block_import_trigger: Option>, proposer_environment: PEnvironment, shards: Vec>, - scheduled_enclave: Arc, - state_handler: Arc, ) -> Result<(Vec, Vec)> where ParentchainBlock: BlockTrait, @@ -297,21 +289,17 @@ where TriggerParentchainBlockImport>, TargetBBlockImportTrigger: TriggerParentchainBlockImport>, - ScheduledEnclave: ScheduledEnclaveUpdater, - StateHandler: HandleState, { debug!("[Aura] Executing aura for slot: {:?}", slot); let mut aura = - Aura::<_, ParentchainBlock, SignedSidechainBlock, PEnvironment, _, _, _, _, _, _>::new( + Aura::<_, ParentchainBlock, SignedSidechainBlock, PEnvironment, _, _, _, _>::new( authority, ocall_api.as_ref().clone(), integritee_block_import_trigger, maybe_target_a_block_import_trigger, maybe_target_b_block_import_trigger, proposer_environment, - scheduled_enclave, - state_handler, ) .with_claim_strategy(SlotClaimStrategy::RoundRobin); diff --git a/tee-worker/litentry/core/assertion-build-v2/src/nft_holder/mod.rs b/tee-worker/litentry/core/assertion-build-v2/src/nft_holder/mod.rs index e503f17721..7056f076dd 100644 --- a/tee-worker/litentry/core/assertion-build-v2/src/nft_holder/mod.rs +++ b/tee-worker/litentry/core/assertion-build-v2/src/nft_holder/mod.rs @@ -197,6 +197,28 @@ mod tests { }) } + fn create_mfan_assertion_logic() -> Box { + Box::new(AssertionLogic::Or { + items: vec![Box::new(AssertionLogic::And { + items: vec![ + Box::new(AssertionLogic::Item { + src: "$network".into(), + op: Op::Equal, + dst: "polygon".into(), + }), + Box::new(AssertionLogic::Item { + src: "$address".into(), + op: Op::Equal, + dst: Web3NftType::MFan + .get_nft_address(Web3Network::Polygon) + .unwrap() + .into(), + }), + ], + })], + }) + } + fn init() -> DataProviderConfig { let _ = env_logger::builder().is_test(true).try_init(); let url = run(0).unwrap(); @@ -307,4 +329,64 @@ mod tests { }, } } + + #[test] + fn build_mfan_holder_works() { + let data_provider_config = init(); + let mut address = + decode_hex("0x49ad262c49c7aa708cc2df262ed53b64a17dd5ee".as_bytes().to_vec()) + .unwrap() + .as_slice() + .try_into() + .unwrap(); + let mut identities: Vec = + vec![(Identity::Evm(address), vec![Web3Network::Polygon])]; + + let mut req = crate_assertion_build_request(Web3NftType::MFan, identities); + match build(&req, Web3NftType::MFan, &data_provider_config) { + Ok(credential) => { + log::info!("build MFan holder done"); + assert_eq!( + *(credential.credential_subject.assertions.first().unwrap()), + AssertionLogic::And { + items: vec![ + create_token_assertion_logic(Web3NftType::MFan), + create_mfan_assertion_logic(), + ] + } + ); + assert_eq!(*(credential.credential_subject.values.first().unwrap()), true); + }, + Err(e) => { + panic!("build MFan holder failed with error {:?}", e); + }, + } + + address = decode_hex("0x45cdb67696802b9d01ed156b883269dbdb9c6239".as_bytes().to_vec()) + .unwrap() + .as_slice() + .try_into() + .unwrap(); + identities = vec![(Identity::Evm(address), vec![Web3Network::Polygon])]; + + req = crate_assertion_build_request(Web3NftType::MFan, identities); + match build(&req, Web3NftType::MFan, &data_provider_config) { + Ok(credential) => { + log::info!("build MFan holder done"); + assert_eq!( + *(credential.credential_subject.assertions.first().unwrap()), + AssertionLogic::And { + items: vec![ + create_token_assertion_logic(Web3NftType::MFan), + create_mfan_assertion_logic(), + ] + } + ); + assert_eq!(*(credential.credential_subject.values.first().unwrap()), false); + }, + Err(e) => { + panic!("build MFan holder failed with error {:?}", e); + }, + } + } } diff --git a/tee-worker/litentry/core/assertion-build-v2/src/platform_user/mod.rs b/tee-worker/litentry/core/assertion-build-v2/src/platform_user/mod.rs index 2039ca1c44..fe459d74be 100644 --- a/tee-worker/litentry/core/assertion-build-v2/src/platform_user/mod.rs +++ b/tee-worker/litentry/core/assertion-build-v2/src/platform_user/mod.rs @@ -93,12 +93,26 @@ mod tests { use litentry_hex_utils::decode_hex; use litentry_primitives::{Identity, IdentityNetworkTuple}; - fn init() -> DataProviderConfig { + fn init(platform_user_type: PlatformUserType) -> DataProviderConfig { let _ = env_logger::builder().is_test(true).try_init(); - let url = run(0).unwrap() + "/karat_dao/"; let mut config = DataProviderConfig::new().unwrap(); - config.set_karat_dao_api_url(url).unwrap(); + + match platform_user_type { + PlatformUserType::KaratDao => { + let url = run(0).unwrap() + "/karat_dao/"; + config.set_karat_dao_api_url(url).unwrap(); + }, + PlatformUserType::MagicCraftStaking => { + let url = run(0).unwrap() + "/magic_craft/"; + config.set_magic_craft_api_url(url).unwrap(); + }, + PlatformUserType::DarenMarket => { + let url = run(0).unwrap() + "/daren_market/"; + config.set_daren_market_api_url(url).unwrap(); + }, + }; + config } @@ -129,11 +143,11 @@ mod tests { assertion_value: bool, data_provider_config: &DataProviderConfig, ) { - let req = crate_assertion_build_request(PlatformUserType::KaratDaoUser, identities); + let req = crate_assertion_build_request(platform_user_type.clone(), identities); match build(&req, platform_user_type.clone(), &data_provider_config) { Ok(credential) => { - log::info!("build karat dao user done"); + log::info!("build platform user: {:?} done", platform_user_type); assert_eq!( *(credential.credential_subject.assertions.first().unwrap()), AssertionLogic::And { @@ -150,14 +164,85 @@ mod tests { ); }, Err(e) => { - panic!("build karat dao user failed with error {:?}", e); + panic!("build platform user: {:?} failed with error {:?}", platform_user_type, e); }, } } #[test] fn build_karat_dao_user_works() { - let data_provider_config = init(); + let data_provider_config = init(PlatformUserType::KaratDao); + + let mut address = + decode_hex("0x49ad262c49c7aa708cc2df262ed53b64a17dd5ee".as_bytes().to_vec()) + .unwrap() + .as_slice() + .try_into() + .unwrap(); + let mut identities: Vec = + vec![(Identity::Evm(address), vec![Web3Network::Ethereum])]; + + build_and_assert_result( + identities, + PlatformUserType::KaratDao, + true, + &data_provider_config, + ); + + address = decode_hex("0x75438d34c9125839c8b08d21b7f3167281659e7c".as_bytes().to_vec()) + .unwrap() + .as_slice() + .try_into() + .unwrap(); + identities = vec![(Identity::Evm(address), vec![Web3Network::Bsc, Web3Network::Ethereum])]; + + build_and_assert_result( + identities, + PlatformUserType::KaratDao, + false, + &data_provider_config, + ); + } + + #[test] + fn build_magic_craft_staking_user_works() { + let data_provider_config = init(PlatformUserType::MagicCraftStaking); + + let mut address = + decode_hex("0x49ad262c49c7aa708cc2df262ed53b64a17dd5ee".as_bytes().to_vec()) + .unwrap() + .as_slice() + .try_into() + .unwrap(); + let mut identities: Vec = + vec![(Identity::Evm(address), vec![Web3Network::Ethereum])]; + + build_and_assert_result( + identities, + PlatformUserType::MagicCraftStaking, + true, + &data_provider_config, + ); + + address = decode_hex("0x75438d34c9125839c8b08d21b7f3167281659e7c".as_bytes().to_vec()) + .unwrap() + .as_slice() + .try_into() + .unwrap(); + identities = vec![(Identity::Evm(address), vec![Web3Network::Bsc, Web3Network::Ethereum])]; + + build_and_assert_result( + identities, + PlatformUserType::MagicCraftStaking, + false, + &data_provider_config, + ); + } + + #[test] + fn build_daren_market_user_works() { + let data_provider_config = init(PlatformUserType::DarenMarket); + let mut address = decode_hex("0x49ad262c49c7aa708cc2df262ed53b64a17dd5ee".as_bytes().to_vec()) .unwrap() @@ -169,7 +254,7 @@ mod tests { build_and_assert_result( identities, - PlatformUserType::KaratDaoUser, + PlatformUserType::DarenMarket, true, &data_provider_config, ); @@ -183,7 +268,7 @@ mod tests { build_and_assert_result( identities, - PlatformUserType::KaratDaoUser, + PlatformUserType::DarenMarket, false, &data_provider_config, ); diff --git a/tee-worker/litentry/core/assertion-build-v2/src/token_holding_amount/mod.rs b/tee-worker/litentry/core/assertion-build-v2/src/token_holding_amount/mod.rs index b5cc3d9811..4082d9f593 100644 --- a/tee-worker/litentry/core/assertion-build-v2/src/token_holding_amount/mod.rs +++ b/tee-worker/litentry/core/assertion-build-v2/src/token_holding_amount/mod.rs @@ -695,4 +695,84 @@ mod tests { }, }; } + + #[test] + fn build_an_holding_amount_works() { + let data_provider_config: DataProviderConfig = init(); + let address = decode_hex("0x75438d34c9125839c8b08d21b7f3167281659e4c".as_bytes().to_vec()) + .unwrap() + .as_slice() + .try_into() + .unwrap(); + let identities = vec![(Identity::Evm(address), vec![Web3Network::Bsc])]; + let req = crate_assertion_build_request(Web3TokenType::An, identities); + match build(&req, Web3TokenType::An, &data_provider_config) { + Ok(credential) => { + log::info!("build an TokenHoldingAmount done"); + assert_eq!( + *(credential.credential_subject.assertions.first().unwrap()), + AssertionLogic::And { + items: vec![ + create_token_assertion_logic(Web3TokenType::An), + create_network_address_assertion_logics(Web3TokenType::An), + Box::new(AssertionLogic::Item { + src: "$holding_amount".into(), + op: Op::GreaterEq, + dst: "100000".into() + }), + Box::new(AssertionLogic::Item { + src: "$holding_amount".into(), + op: Op::LessThan, + dst: "900000".into() + }) + ] + } + ); + assert_eq!(*(credential.credential_subject.values.first().unwrap()), true); + }, + Err(e) => { + panic!("build an TokenHoldingAmount failed with error {:?}", e); + }, + }; + } + + #[test] + fn build_tuna_holding_amount_works() { + let data_provider_config: DataProviderConfig = init(); + let address = decode_hex("0x75438d34c9125839c8b08d21b7f3167281659e5c".as_bytes().to_vec()) + .unwrap() + .as_slice() + .try_into() + .unwrap(); + let identities = vec![(Identity::Evm(address), vec![Web3Network::Ethereum])]; + let req = crate_assertion_build_request(Web3TokenType::Tuna, identities); + match build(&req, Web3TokenType::Tuna, &data_provider_config) { + Ok(credential) => { + log::info!("build tuna TokenHoldingAmount done"); + assert_eq!( + *(credential.credential_subject.assertions.first().unwrap()), + AssertionLogic::And { + items: vec![ + create_token_assertion_logic(Web3TokenType::Tuna), + create_network_address_assertion_logics(Web3TokenType::Tuna), + Box::new(AssertionLogic::Item { + src: "$holding_amount".into(), + op: Op::GreaterEq, + dst: "1000".into() + }), + Box::new(AssertionLogic::Item { + src: "$holding_amount".into(), + op: Op::LessThan, + dst: "2000".into() + }) + ] + } + ); + assert_eq!(*(credential.credential_subject.values.first().unwrap()), true); + }, + Err(e) => { + panic!("build tuna TokenHoldingAmount failed with error {:?}", e); + }, + }; + } } diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/.gitignore b/tee-worker/litentry/core/assertion-build/src/dynamic/.gitignore index 1a440b2a3e..d8944873a1 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/.gitignore +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/.gitignore @@ -1,3 +1,4 @@ .deps artifacts .prettierrc.json +!*.sol diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/A20.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/A20.sol index 6408adde2f..10b49dda7c 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/A20.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/A20.sol @@ -21,6 +21,7 @@ pragma solidity ^0.8.8; import "./libraries/AssertionLogic.sol"; import "./libraries/Http.sol"; import "./libraries/Identities.sol"; +import "./libraries/Logging.sol"; import "./libraries/Utils.sol"; import "./DynamicAssertion.sol"; @@ -40,6 +41,7 @@ contract A20 is DynamicAssertion { bool ) { + Logging.info("begin generate VC for A20"); string memory description = "The user is an early bird user of the IdentityHub EVM version and has generated at least 1 credential during 2023 Aug 14th ~ Aug 21st."; string memory assertion_type = "IDHub EVM Version Early Bird"; @@ -82,6 +84,7 @@ contract A20 is DynamicAssertion { } } + Logging.info("begin create assertion for A20"); AssertionLogic.Condition memory condition = AssertionLogic.Condition( "$has_joined", AssertionLogic.Op.Equal, diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/A6.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/A6.sol index f67691ee17..fb896665a5 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/A6.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/A6.sol @@ -18,7 +18,7 @@ pragma solidity ^0.8.8; -import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/utils/Strings.sol"; +import "./openzeppelin/Strings.sol"; import "./libraries/AssertionLogic.sol"; import "./libraries/Http.sol"; import "./libraries/Identities.sol"; diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/libraries/Logging.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/libraries/Logging.sol new file mode 100644 index 0000000000..999c1d922f --- /dev/null +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/libraries/Logging.sol @@ -0,0 +1,71 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.8; + +enum LoggingLevel { + Debug, + Info, + Warn, + Err, + Fatal +} + +library Logging { + function debug(string memory message) internal { + log(LoggingLevel.Debug, message); + } + + function info(string memory message) internal { + log(LoggingLevel.Info, message); + } + + function warn(string memory message) internal { + log(LoggingLevel.Warn, message); + } + + function fatal(string memory message) internal { + log(LoggingLevel.Fatal, message); + } + + function error(string memory message) internal { + log(LoggingLevel.Err, message); + } + + function log(LoggingLevel level, string memory message) internal { + bytes memory encoded_params = abi.encode(level, message); + uint256 encoded_params_len = encoded_params.length; + + assembly { + let memPtr := mload(0x40) + if iszero( + call( + not(0), + 0x041A, + 0, + add(encoded_params, 0x20), + encoded_params_len, + memPtr, + 0x40 + ) + ) { + revert(0, 0) + } + } + } +} diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/libraries/StringShift.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/libraries/StringShift.sol new file mode 100644 index 0000000000..ce4b70d940 --- /dev/null +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/libraries/StringShift.sol @@ -0,0 +1,119 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.0; +import "../openzeppelin/Strings.sol"; +import "../openzeppelin/math/Math.sol"; +library StringShift { + /** + * @dev Converts a uint256 input to a string and shifts the decimal point to the left by the specified number of places. + * @param value The uint256 parameter to be processed. + * @param decimal The number of decimal places to shift. + * @return The processed string. + */ + function toShiftedString( + uint256 value, + uint256 decimal + ) internal pure returns (string memory) { + // Convert uint256 to string + + if (value == 0) { + return "0"; + } else { + string memory str = Strings.toString(value); + + // Calculate the position to insert the decimal point + uint256 len = bytes(str).length; + uint256 digit = Math.log10(decimal); + + if (len <= digit) { + // If the length is less than or equal to the number of digits, pad with leading zeros and add '0.' + string memory leadingZeros = new string(digit - len); + for (uint256 i = 0; i < digit - len; i++) { + leadingZeros = string(abi.encodePacked("0", leadingZeros)); + } + str = string(abi.encodePacked("0.", leadingZeros, str)); + } else { + // Otherwise, insert the decimal point at the correct position + str = string( + abi.encodePacked( + substring(str, 0, len - digit), + ".", + substring(str, len - digit, len) + ) + ); + } + + // Remove trailing zeros after the decimal point + str = removeTrailingZeros(str); + + return str; + } + } + + /** + * @dev Extracts a substring from a given string. + * @param str The original string. + * @param start The starting position of the original string. + * @param end The ending position of the original string. + * @return The extracted substring. + */ + function substring( + string memory str, + uint256 start, + uint256 end + ) internal pure returns (string memory) { + bytes memory strBytes = bytes(str); + bytes memory result = new bytes(end - start); + for (uint256 i = start; i < end; i++) { + result[i - start] = strBytes[i]; + } + return string(result); + } + + /** + * @dev Removes trailing zeros after the decimal point in a string. + * @param str The input string. + * @return The processed string with trailing zeros removed. + */ + function removeTrailingZeros( + string memory str + ) internal pure returns (string memory) { + bytes memory strBytes = bytes(str); + uint256 len = strBytes.length; + + // Traverse from the end to find the position of the first non-zero character + uint256 newLen = len; + while (newLen > 0 && strBytes[newLen - 1] == "0") { + newLen--; + } + + // If the last character is a decimal point, remove it as well + if (newLen > 0 && strBytes[newLen - 1] == ".") { + newLen--; + } + + // Create a new byte array and copy the content + bytes memory trimmedBytes = new bytes(newLen); + for (uint256 i = 0; i < newLen; i++) { + trimmedBytes[i] = strBytes[i]; + } + + return string(trimmedBytes); + } +} diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/openzeppelin/Strings.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/openzeppelin/Strings.sol new file mode 100644 index 0000000000..e62b10f3c0 --- /dev/null +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/openzeppelin/Strings.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) + +pragma solidity ^0.8.0; + +import "./math/Math.sol"; +import "./math/SignedMath.sol"; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _SYMBOLS = "0123456789abcdef"; + uint8 private constant _ADDRESS_LENGTH = 20; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toString(int256 value) internal pure returns (string memory) { + return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return keccak256(bytes(a)) == keccak256(bytes(b)); + } +} \ No newline at end of file diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/openzeppelin/math/Math.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/openzeppelin/math/Math.sol new file mode 100644 index 0000000000..4fa703ac75 --- /dev/null +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/openzeppelin/math/Math.sol @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + enum Rounding { + Down, // Toward negative infinity + Up, // Toward infinity + Zero // Toward zero + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds up instead + * of rounding down. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b - 1) / b can overflow on addition, so we distribute. + return a == 0 ? 0 : (a - 1) / b + 1; + } + + /** + * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 + * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) + * with further edits by Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod0 := mul(x, y) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division. + if (prod1 == 0) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + require(denominator > prod1, "Math: mulDiv overflow"); + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. + // See https://cs.stackexchange.com/q/138556/92363. + + // Does not overflow because the denominator cannot be zero at this stage in the function. + uint256 twos = denominator & (~denominator + 1); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works + // in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + uint256 result = mulDiv(x, y, denominator); + if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { + result += 1; + } + return result; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. + * + * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). + */ + function sqrt(uint256 a) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. + // + // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have + // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 1); + + // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, + // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at + // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision + // into the expected uint128 result. + unchecked { + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + return min(result, a / result); + } + } + + /** + * @notice Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256, rounded down, of a positive value. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); + } + } +} \ No newline at end of file diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/openzeppelin/math/SignedMath.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/openzeppelin/math/SignedMath.sol new file mode 100644 index 0000000000..c611063c70 --- /dev/null +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/openzeppelin/math/SignedMath.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Standard signed math utilities missing in the Solidity language. + */ +library SignedMath { + /** + * @dev Returns the largest of two signed numbers. + */ + function max(int256 a, int256 b) internal pure returns (int256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two signed numbers. + */ + function min(int256 a, int256 b) internal pure returns (int256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two signed numbers without overflow. + * The result is rounded towards zero. + */ + function average(int256 a, int256 b) internal pure returns (int256) { + // Formula from the book "Hacker's Delight" + int256 x = (a & b) + ((a ^ b) >> 1); + return x + (int256(uint256(x) >> 255) & (a ^ b)); + } + + /** + * @dev Returns the absolute unsigned value of a signed value. + */ + function abs(int256 n) internal pure returns (uint256) { + unchecked { + // must be unchecked in order to support `n = type(int256).min` + return uint256(n >= 0 ? n : -n); + } + } +} \ No newline at end of file diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/tests/LoggingTest.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/tests/LoggingTest.sol new file mode 100644 index 0000000000..0bf8f5e64c --- /dev/null +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/tests/LoggingTest.sol @@ -0,0 +1,27 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.8; + +import "../libraries/Logging.sol"; + +contract LoggingTest { + function callLogging(uint8 level, string memory message) public { + Logging.log(LoggingLevel(level), message); + } +} diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/AchainableClient.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/AchainableClient.sol index bec1799a36..0dc25d335e 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/AchainableClient.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/AchainableClient.sol @@ -20,7 +20,8 @@ pragma solidity ^0.8.8; import "../libraries/Http.sol"; import "../libraries/Json.sol"; -import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/utils/Strings.sol"; +import "../openzeppelin/Strings.sol"; + struct DisplayItem { string text; diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/GeniidataClient.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/GeniidataClient.sol index 4b564ed80d..c9b78ea3f2 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/GeniidataClient.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/GeniidataClient.sol @@ -19,18 +19,20 @@ pragma solidity ^0.8.8; import "../libraries/Http.sol"; +import "../libraries/Identities.sol"; import "../libraries/Utils.sol"; + library GeniidataClient { function getTokenBalance( string[] memory secrets, - string memory url, string memory identityString, string memory tokenName, uint8 tokenDecimals ) internal returns (uint256) { string memory encodePackedUrl = string( abi.encodePacked( - url, + // test against mock server => "http://localhost:19529/api/1/brc20/balance" + "https://api.geniidata.com/api/1/brc20/balance", "?tick=", tokenName, "&address=", @@ -58,4 +60,13 @@ library GeniidataClient { } return 0; } + + function isSupportedNetwork(uint32 network) internal pure returns (bool) { + return + network == Web3Networks.BitcoinP2tr || + network == Web3Networks.BitcoinP2pkh || + network == Web3Networks.BitcoinP2sh || + network == Web3Networks.BitcoinP2wpkh || + network == Web3Networks.BitcoinP2wsh; + } } diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/MoralisClient.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/MoralisClient.sol index 45ab776acc..42ad05ce7f 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/MoralisClient.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/MoralisClient.sol @@ -20,7 +20,7 @@ pragma solidity ^0.8.8; import "../libraries/Http.sol"; import "../libraries/Json.sol"; -import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/utils/Strings.sol"; +import "../openzeppelin/Strings.sol"; struct SolanaTokenBalance { string mint; diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/NoderealClient.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/NoderealClient.sol index 6df76cee62..73bdf98ff4 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/NoderealClient.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/NoderealClient.sol @@ -19,10 +19,12 @@ pragma solidity ^0.8.8; import "../libraries/Http.sol"; +import "../libraries/Identities.sol"; import "../libraries/Utils.sol"; + library NoderealClient { function getTokenBalance( - string memory url, + uint32 network, string[] memory secrets, string memory tokenContractAddress, string memory account @@ -31,7 +33,7 @@ library NoderealClient { string memory request; string memory encodePackedUrl = string( - abi.encodePacked(url, secrets[0]) + abi.encodePacked(getNetworkUrl(network), secrets[0]) ); if ( keccak256(bytes(tokenContractAddress)) == keccak256("Native Token") @@ -69,5 +71,21 @@ library NoderealClient { } else { return (false, 0); } - } + } + + function isSupportedNetwork(uint32 network) internal pure returns (bool) { + return network == Web3Networks.Bsc || network == Web3Networks.Ethereum; + } + + function getNetworkUrl(uint32 network) + internal + pure + returns (string memory url) + { + if (network == Web3Networks.Bsc) { + url = "https://bsc-mainnet.nodereal.io/v1/"; + } else if (network == Web3Networks.Ethereum) { + url = "https://eth-mainnet.nodereal.io/v1/"; + } + } } diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/TokenHoldingAmount.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/TokenHoldingAmount.sol index 9867889ce1..957b5ee14d 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/TokenHoldingAmount.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/TokenHoldingAmount.sol @@ -18,11 +18,12 @@ pragma solidity ^0.8.8; -import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/utils/Strings.sol"; +import "../openzeppelin/Strings.sol"; import "../libraries/AssertionLogic.sol"; import "../libraries/Identities.sol"; import "../DynamicAssertion.sol"; import "./Constants.sol"; +import "../libraries/StringShift.sol"; abstract contract TokenHoldingAmount is DynamicAssertion { mapping(string => string) internal tokenNames; @@ -91,7 +92,7 @@ abstract contract TokenHoldingAmount is DynamicAssertion { uint256 networksLength = identity.networks.length; for (uint32 j = 0; j < networksLength; j++) { uint32 network = identity.networks[j]; - if (isSupportedNetwork(network)) { + if (isSupportedNetwork(tokenName, network)) { total_balance += queryBalance( identity, network, @@ -157,7 +158,7 @@ abstract contract TokenHoldingAmount is DynamicAssertion { 1, variable, AssertionLogic.Op.GreaterEq, - Strings.toString(min / Constants.decimals_factor) + StringShift.toShiftedString(min, Constants.decimals_factor) ); if (max > 0) { AssertionLogic.andOp( @@ -165,7 +166,10 @@ abstract contract TokenHoldingAmount is DynamicAssertion { 2, variable, AssertionLogic.Op.LessThan, - Strings.toString(uint256(max) / Constants.decimals_factor) + StringShift.toShiftedString( + uint256(max), + Constants.decimals_factor + ) ); } @@ -178,8 +182,9 @@ abstract contract TokenHoldingAmount is DynamicAssertion { function getTokenDecimals() internal pure virtual returns (uint8); function isSupportedNetwork( + string memory tokenName, uint32 network - ) internal pure virtual returns (bool); + ) internal view virtual returns (bool); function queryBalance( Identity memory identity, diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/TokenQueryLogic.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/TokenQueryLogic.sol index e70c002eca..0e12b8e687 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/TokenQueryLogic.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/TokenQueryLogic.sol @@ -23,26 +23,14 @@ import "../libraries/Utils.sol"; import { TokenHoldingAmount } from "./TokenHoldingAmount.sol"; import { NoderealClient } from "./NoderealClient.sol"; import { GeniidataClient } from "./GeniidataClient.sol"; -abstract contract TokenLogic is TokenHoldingAmount { - mapping(uint32 => string) internal networkUrls; - mapping(uint32 => bool) private queriedNetworks; + +abstract contract TokenQueryLogic is TokenHoldingAmount { mapping(string => mapping(uint32 => string)) tokenAddresses; mapping(string => string) internal tokenBscAddress; mapping(string => string) internal tokenEthereumAddress; mapping(string => uint32[]) internal tokenNetworks; - constructor() { - networkUrls[Web3Networks.Bsc] = "https://bsc-mainnet.nodereal.io/v1/"; // test against mock server => "http://localhost:19530/nodereal_jsonrpc/" - networkUrls[ - Web3Networks.Ethereum - ] = "https://eth-mainnet.nodereal.io/v1/"; // test against mock server => "http://localhost:19530/nodereal_jsonrpc/" - - networkUrls[ - Web3Networks.BitcoinP2tr - ] = "https://api.geniidata.com/api/1/brc20/balance"; // test against mock server => "http://localhost:19529/api/1/brc20/balance" - // Add more networks as needed - } - + // TODO fix it for erc20 token, same token for different networks has different decimals. function getTokenDecimals() internal pure override returns (uint8) { return 18; } @@ -57,44 +45,29 @@ abstract contract TokenLogic is TokenHoldingAmount { .identityToString(network, identity.value); if (identityToStringSuccess) { - string memory url; - uint32[] memory networks = tokenNetworks[tokenName]; uint256 totalBalance = 0; - for (uint32 i = 0; i < networks.length; i++) { - // Check if this network has been queried - url = networkUrls[networks[i]]; - - if (!queriedNetworks[networks[i]]) { - string memory _tokenContractAddress = tokenAddresses[ - tokenName - ][networks[i]]; - if (networks[i] == Web3Networks.BitcoinP2tr) { - uint256 balance = GeniidataClient.getTokenBalance( - secrets, - url, - identityString, - tokenName, - getTokenDecimals() - ); - totalBalance += balance; - } else if ( - networks[i] == Web3Networks.Bsc || - networks[i] == Web3Networks.Ethereum - ) { - (bool success, uint256 balance) = NoderealClient - .getTokenBalance( - url, - secrets, - _tokenContractAddress, - identityString - ); - if (success) { - totalBalance += balance; - } - } - // Mark this network as queried - queriedNetworks[networks[i]] = true; + string memory tokenContractAddress = tokenAddresses[tokenName][ + network + ]; + if (GeniidataClient.isSupportedNetwork(network)) { + uint256 balance = GeniidataClient.getTokenBalance( + secrets, + identityString, + tokenName, + getTokenDecimals() + ); + totalBalance += balance; + } else if (NoderealClient.isSupportedNetwork(network)) { + (bool success, uint256 balance) = NoderealClient + .getTokenBalance( + network, + secrets, + tokenContractAddress, + identityString + ); + if (success) { + totalBalance += balance; } } return totalBalance; @@ -102,12 +75,18 @@ abstract contract TokenLogic is TokenHoldingAmount { return 0; } - function isSupportedNetwork( - uint32 network - ) internal pure override returns (bool) { - return - network == Web3Networks.Bsc || - network == Web3Networks.Ethereum || - network == Web3Networks.BitcoinP2tr; + function isSupportedNetwork(string memory tokenName, uint32 network) + internal + view + override + returns (bool) + { + uint32[] memory networks = tokenNetworks[tokenName]; + for (uint32 i = 0; i < networks.length; i++) { + if (network == networks[i]) { + return true; + } + } + return false; } } diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/BRC20.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/BRC20.sol new file mode 100644 index 0000000000..22b4473ccb --- /dev/null +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/BRC20.sol @@ -0,0 +1,35 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.8; + +import "../Constants.sol"; +import "../../libraries/Identities.sol"; + + +library BRC20 { + function getDefaultTokenNetworks() internal pure returns (uint32[] memory) { + uint32[] memory networks = new uint32[](5); + networks[0] = Web3Networks.BitcoinP2tr; + networks[1] = Web3Networks.BitcoinP2pkh; + networks[2] = Web3Networks.BitcoinP2sh; + networks[3] = Web3Networks.BitcoinP2wpkh; + networks[4] = Web3Networks.BitcoinP2wsh; + return networks; + } +} diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Btcs.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Btcs.sol index 2f3b309b16..0fbbadb08a 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Btcs.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Btcs.sol @@ -18,8 +18,9 @@ pragma solidity ^0.8.8; -import "../Constants.sol"; import "../../libraries/Identities.sol"; +import "../Constants.sol"; +import "./BRC20.sol"; library Btcs { function getTokenName() internal pure returns (string memory) { @@ -39,9 +40,8 @@ library Btcs { ranges[8] = 800 * Constants.decimals_factor; return ranges; } + function getTokenNetworks() internal pure returns (uint32[] memory) { - uint32[] memory networks = new uint32[](1); - networks[0] = Web3Networks.BitcoinP2tr; - return networks; + return BRC20.getDefaultTokenNetworks(); } } diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Cats.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Cats.sol index 0a4b5cb31f..228025ef8e 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Cats.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Cats.sol @@ -18,8 +18,9 @@ pragma solidity ^0.8.8; -import "../Constants.sol"; import "../../libraries/Identities.sol"; +import "../Constants.sol"; +import "./BRC20.sol"; library Cats { function getTokenName() internal pure returns (string memory) { @@ -38,9 +39,8 @@ library Cats { ranges[7] = 800000 * Constants.decimals_factor; return ranges; } + function getTokenNetworks() internal pure returns (uint32[] memory) { - uint32[] memory networks = new uint32[](1); - networks[0] = Web3Networks.BitcoinP2tr; - return networks; + return BRC20.getDefaultTokenNetworks(); } } diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Long.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Long.sol index 60fbef5852..9d60fe0d54 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Long.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Long.sol @@ -18,8 +18,9 @@ pragma solidity ^0.8.8; -import "../Constants.sol"; import "../../libraries/Identities.sol"; +import "../Constants.sol"; +import "./BRC20.sol"; library Long { function getTokenName() internal pure returns (string memory) { @@ -39,9 +40,8 @@ library Long { ranges[8] = 3000 * Constants.decimals_factor; return ranges; } + function getTokenNetworks() internal pure returns (uint32[] memory) { - uint32[] memory networks = new uint32[](1); - networks[0] = Web3Networks.BitcoinP2tr; - return networks; + return BRC20.getDefaultTokenNetworks(); } } diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Mmss.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Mmss.sol index 37dc39493a..4f515a0a25 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Mmss.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Mmss.sol @@ -18,8 +18,9 @@ pragma solidity ^0.8.8; -import "../Constants.sol"; import "../../libraries/Identities.sol"; +import "../Constants.sol"; +import "./BRC20.sol"; library Mmss { function getTokenName() internal pure returns (string memory) { @@ -39,9 +40,8 @@ library Mmss { ranges[8] = 2000 * Constants.decimals_factor; return ranges; } + function getTokenNetworks() internal pure returns (uint32[] memory) { - uint32[] memory networks = new uint32[](1); - networks[0] = Web3Networks.BitcoinP2tr; - return networks; + return BRC20.getDefaultTokenNetworks(); } } diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Ordi.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Ordi.sol index a9e520015a..aeb0869782 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Ordi.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Ordi.sol @@ -18,8 +18,9 @@ pragma solidity ^0.8.8; -import "../Constants.sol"; import "../../libraries/Identities.sol"; +import "../Constants.sol"; +import "./BRC20.sol"; library Ordi { function getTokenName() internal pure returns (string memory) { @@ -38,9 +39,8 @@ library Ordi { ranges[7] = 500 * Constants.decimals_factor; return ranges; } + function getTokenNetworks() internal pure returns (uint32[] memory) { - uint32[] memory networks = new uint32[](1); - networks[0] = Web3Networks.BitcoinP2tr; - return networks; + return BRC20.getDefaultTokenNetworks(); } } diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Rats.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Rats.sol index 9ea1bd83f3..94b53f3e7d 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Rats.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Rats.sol @@ -18,8 +18,9 @@ pragma solidity ^0.8.8; -import "../Constants.sol"; import "../../libraries/Identities.sol"; +import "../Constants.sol"; +import "./BRC20.sol"; library Rats { function getTokenName() internal pure returns (string memory) { @@ -39,9 +40,8 @@ library Rats { ranges[8] = 2000000 * Constants.decimals_factor; return ranges; } + function getTokenNetworks() internal pure returns (uint32[] memory) { - uint32[] memory networks = new uint32[](1); - networks[0] = Web3Networks.BitcoinP2tr; - return networks; + return BRC20.getDefaultTokenNetworks(); } } diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Sats.sol b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Sats.sol index 27f6772425..39e2de7b45 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Sats.sol +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/contracts/token_holding_amount/brc20/Sats.sol @@ -18,8 +18,9 @@ pragma solidity ^0.8.8; -import "../Constants.sol"; import "../../libraries/Identities.sol"; +import "../Constants.sol"; +import "./BRC20.sol"; library Sats { function getTokenName() internal pure returns (string memory) { @@ -39,9 +40,8 @@ library Sats { ranges[8] = 6000000000 * Constants.decimals_factor; return ranges; } + function getTokenNetworks() internal pure returns (uint32[] memory) { - uint32[] memory networks = new uint32[](1); - networks[0] = Web3Networks.BitcoinP2tr; - return networks; + return BRC20.getDefaultTokenNetworks(); } } diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/mod.rs b/tee-worker/litentry/core/assertion-build/src/dynamic/mod.rs index cec5202e25..5cc4c19710 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/mod.rs +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/mod.rs @@ -29,16 +29,20 @@ pub fn build< SC: AssertionLogicRepository)>, >( req: &AssertionBuildRequest, - smart_contract_id: SC::Id, - smart_contract_params: DynamicParams, + params: DynamicParams, repository: Arc, -) -> Result { +) -> Result<(Credential, Vec)> { let executor = EvmAssertionExecutor { assertion_repository: repository }; + let execution_params = params.clone(); let result = executor - .execute(smart_contract_id, smart_contract_params.clone().into(), &req.identities) + .execute( + execution_params.smart_contract_id, + execution_params.smart_contract_params.map(|v| v.into()).unwrap_or_default(), + &req.identities, + ) .map_err(|e| { Error::RequestVCFailed( - Assertion::Dynamic(smart_contract_id, smart_contract_params.clone()), + Assertion::Dynamic(params.clone()), ErrorDetail::StfError(ErrorString::truncate_from(e.into())), ) })?; @@ -54,7 +58,7 @@ pub fn build< for assertion in result.assertions { let logic: AssertionLogic = serde_json::from_str(&assertion).map_err(|e| { Error::RequestVCFailed( - Assertion::Dynamic(smart_contract_id, smart_contract_params.clone()), + Assertion::Dynamic(params.clone()), ErrorDetail::StfError(ErrorString::truncate_from(format!("{}", e).into())), ) })?; @@ -68,14 +72,12 @@ pub fn build< result.schema_url, result.meet, ); - Ok(credential_unsigned) + + Ok((credential_unsigned, if params.return_log { result.contract_logs } else { vec![] })) }, Err(e) => { error!("Generate unsigned credential failed {:?}", e); - Err(Error::RequestVCFailed( - Assertion::Dynamic(smart_contract_id, smart_contract_params), - e.into_error_detail(), - )) + Err(Error::RequestVCFailed(Assertion::Dynamic(params), e.into_error_detail())) }, } } @@ -87,7 +89,9 @@ pub mod assertion_test { use lc_mock_server::run; use lc_stf_task_sender::AssertionBuildRequest; use litentry_hex_utils::decode_hex; - use litentry_primitives::{DynamicParams, Identity, IdentityString, Web3Network}; + use litentry_primitives::{ + DynamicContractParams, DynamicParams, Identity, IdentityString, Web3Network, + }; use sp_core::{crypto::AccountId32, H160}; #[test] @@ -105,11 +109,16 @@ pub mod assertion_test { .into(), ); + let dynamic_params = DynamicParams { + smart_contract_id: hash(1), + smart_contract_params: None, + return_log: true, + }; let request = AssertionBuildRequest { shard: Default::default(), signer: AccountId32::new([0; 32]), who: Identity::Twitter(IdentityString::new(vec![])), - assertion: Assertion::Dynamic(hash(1), DynamicParams::truncate_from(vec![])), + assertion: Assertion::Dynamic(dynamic_params.clone()), identities: vec![(twitter_identity, vec![]), (substrate_identity, vec![])], top_hash: Default::default(), parachain_block_number: Default::default(), @@ -124,14 +133,16 @@ pub mod assertion_test { let repository = InMemorySmartContractRepo::new(); // when - let credential = - build(&request, hash(1), DynamicParams::truncate_from(vec![]), repository.into()) - .unwrap(); + let (credential, vc_logs) = build(&request, dynamic_params, repository.into()).unwrap(); + for log in &vc_logs { + println!("{}", log); + } println!("Credential is: {:?}", credential); // then assert!(credential.credential_subject.values[0]); + // assert!(vc_logs.len() == 0); } #[test] @@ -141,11 +152,16 @@ pub mod assertion_test { let twitter_identity = Identity::Twitter(IdentityString::new(vec![])); let substrate_identity = Identity::Substrate(AccountId32::new([0; 32]).into()); + let dynamic_params = DynamicParams { + smart_contract_id: hash(0), + smart_contract_params: None, + return_log: false, + }; let request = AssertionBuildRequest { shard: Default::default(), signer: AccountId32::new([0; 32]), who: Identity::Twitter(IdentityString::new(vec![])), - assertion: Assertion::Dynamic(hash(0), DynamicParams::truncate_from(vec![])), + assertion: Assertion::Dynamic(dynamic_params.clone()), identities: vec![(twitter_identity, vec![]), (substrate_identity, vec![])], top_hash: Default::default(), parachain_block_number: Default::default(), @@ -160,9 +176,7 @@ pub mod assertion_test { let repository = InMemorySmartContractRepo::new(); // when - let credential = - build(&request, hash(0), DynamicParams::truncate_from(vec![]), repository.into()) - .unwrap(); + let (credential, _) = build(&request, dynamic_params, repository.into()).unwrap(); println!("Credential is: {:?}", credential); @@ -179,11 +193,16 @@ pub mod assertion_test { Identity::Twitter(IdentityString::new("twitterdev".as_bytes().to_vec())); let substrate_identity = Identity::Substrate(AccountId32::new([0; 32]).into()); + let dynamic_params = DynamicParams { + smart_contract_id: hash(2), + smart_contract_params: None, + return_log: false, + }; let request = AssertionBuildRequest { shard: Default::default(), signer: AccountId32::new([0; 32]), who: Identity::Twitter(IdentityString::new(vec![])), - assertion: Assertion::Dynamic(hash(2), DynamicParams::truncate_from(vec![])), + assertion: Assertion::Dynamic(dynamic_params.clone()), identities: vec![(twitter_identity, vec![]), (substrate_identity, vec![])], top_hash: Default::default(), parachain_block_number: Default::default(), @@ -198,9 +217,7 @@ pub mod assertion_test { let repository = InMemorySmartContractRepo::new(); // when - let credential = - build(&request, hash(2), DynamicParams::truncate_from(vec![]), repository.into()) - .unwrap(); + let (credential, _) = build(&request, dynamic_params, repository.into()).unwrap(); println!("Credential is: {:?}", credential); @@ -214,11 +231,16 @@ pub mod assertion_test { // given let twitter_identity = Identity::Twitter(IdentityString::new(vec![])); + let dynamic_params = DynamicParams { + smart_contract_id: hash(0), + smart_contract_params: None, + return_log: false, + }; let request = AssertionBuildRequest { shard: Default::default(), signer: AccountId32::new([0; 32]), who: Identity::Twitter(IdentityString::new(vec![])), - assertion: Assertion::Dynamic(hash(0), DynamicParams::truncate_from(vec![])), + assertion: Assertion::Dynamic(dynamic_params.clone()), identities: vec![(twitter_identity, vec![])], top_hash: Default::default(), parachain_block_number: Default::default(), @@ -233,9 +255,7 @@ pub mod assertion_test { let repository = InMemorySmartContractRepo::new(); // when - let credential = - build(&request, hash(0), DynamicParams::truncate_from(vec![]), repository.into()) - .unwrap(); + let (credential, _) = build(&request, dynamic_params, repository.into()).unwrap(); // then assert!(!credential.credential_subject.values[0]); @@ -259,15 +279,19 @@ pub mod assertion_test { let network = Web3Network::BitcoinP2tr; let identities = vec![(Identity::Bitcoin(address), vec![network])]; - let smart_contract_id = hash(3); - let smart_contract_params = - DynamicParams::truncate_from(ethabi::encode(&[ethabi::Token::String("ordi".into())])); + let dynamic_params = DynamicParams { + smart_contract_id: hash(3), + smart_contract_params: Some(DynamicContractParams::truncate_from(ethabi::encode(&[ + ethabi::Token::String("ordi".into()), + ]))), + return_log: false, + }; let request = AssertionBuildRequest { shard: Default::default(), signer: AccountId32::new([0; 32]), who: Identity::Substrate(AccountId32::new([0; 32]).into()), - assertion: Assertion::Dynamic(smart_contract_id, smart_contract_params.clone()), + assertion: Assertion::Dynamic(dynamic_params.clone()), identities, top_hash: Default::default(), parachain_block_number: Default::default(), @@ -282,9 +306,7 @@ pub mod assertion_test { let repository = InMemorySmartContractRepo::new(); // when - let credential = - build(&request, smart_contract_id, smart_contract_params.clone(), repository.into()) - .unwrap(); + let (credential, _) = build(&request, dynamic_params, repository.into()).unwrap(); println!("Credential is: {:?}", credential); diff --git a/tee-worker/litentry/core/assertion-build/src/dynamic/repository.rs b/tee-worker/litentry/core/assertion-build/src/dynamic/repository.rs index 7e6a613782..1988f64b3f 100644 --- a/tee-worker/litentry/core/assertion-build/src/dynamic/repository.rs +++ b/tee-worker/litentry/core/assertion-build/src/dynamic/repository.rs @@ -57,7 +57,7 @@ impl InMemorySmartContractRepo { map.insert( hash(1), ( - hex::decode("608060405234801561001057600080fd5b506118af806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063b4e4c68514610030575b600080fd5b61004a60048036038101906100459190610ec0565b610064565b60405161005b959493929190611116565b60405180910390f35b6060806060806000806040518060c00160405280608681526020016117f460869139905060006040518060400160405280601c81526020017f49444875622045564d2056657273696f6e204561726c7920426972640000000081525090506040518060a001604052806075815260200161177f60759139600090805190602001906100f092919061089c565b506000805b8b51811015610262576101218c828151811061011457610113611185565b5b6020026020010151610426565b1561024e576000806101508e848151811061013f5761013e611185565b5b602002602001015160200151610458565b91509150811561023e578161016657505061024f565b6000816040516020016101799190611288565b604051602081830303815290604052905060006040518060400160405280600a81526020017f2f6861734a6f696e656400000000000000000000000000000000000000000000815250905060008067ffffffffffffffff8111156101e0576101df610983565b5b60405190808252806020026020018201604052801561021957816020015b610206610922565b8152602001906001900390816101fe5790505b50905060008061022a8585856104be565b915091508115610238578098505b50505050505b831561024b575050610262565b50505b5b808061025a906112e3565b9150506100f5565b50600060405180606001604052806040518060400160405280600b81526020017f246861735f6a6f696e65640000000000000000000000000000000000000000008152508152602001600460058111156102bf576102be61132c565b5b81526020016040518060400160405280600481526020017f747275650000000000000000000000000000000000000000000000000000000081525081525090506000600167ffffffffffffffff81111561031c5761031b610983565b5b60405190808252806020026020018201604052801561034f57816020015b606081526020019060019003908161033a5790505b50905061035b82610534565b8160008151811061036f5761036e611185565b5b602002602001018190525084848260008681805461038c9061138a565b80601f01602080910402602001604051908101604052809291908181526020018280546103b89061138a565b80156104055780601f106103da57610100808354040283529160200191610405565b820191906000526020600020905b8154815290600101906020018083116103e857829003601f168201915b50505050509150995099509950995099505050505050939792965093509350565b600061043182610575565b80610441575061044082610589565b5b8061045157506104508261059d565b5b9050919050565b6000606060008360405160200161046f9190611411565b6040516020818303038152906040529050600081519050604051611000818360208601600061041b600019f16104a457600080fd5b805194506040810193506110008101604052505050915091565b60008060008060008787876040516020016104db93929190611539565b6040516020818303038152906040529050600081519050604051604081836020860160006103e9600019f161050f57600080fd5b8051945060208101519350604081016040525083839550955050505050935093915050565b6060816000015161054883602001516105b1565b836040015160405160200161055f939291906116b5565b6040516020818303038152906040529050919050565b600061058282600361086e565b9050919050565b600061059682600461086e565b9050919050565b60006105aa82600561086e565b9050919050565b6060600460058111156105c7576105c661132c565b5b8260058111156105da576105d961132c565b5b141561061d576040518060400160405280600281526020017f3d3d0000000000000000000000000000000000000000000000000000000000008152509050610869565b600060058111156106315761063061132c565b5b8260058111156106445761064361132c565b5b1415610687576040518060400160405280600181526020017f3e000000000000000000000000000000000000000000000000000000000000008152509050610869565b6001600581111561069b5761069a61132c565b5b8260058111156106ae576106ad61132c565b5b14156106f1576040518060400160405280600181526020017f3c000000000000000000000000000000000000000000000000000000000000008152509050610869565b600260058111156107055761070461132c565b5b8260058111156107185761071761132c565b5b141561075b576040518060400160405280600281526020017f3e3d0000000000000000000000000000000000000000000000000000000000008152509050610869565b6003600581111561076f5761076e61132c565b5b8260058111156107825761078161132c565b5b14156107c5576040518060400160405280600281526020017f3c3d0000000000000000000000000000000000000000000000000000000000008152509050610869565b6005808111156107d8576107d761132c565b5b8260058111156107eb576107ea61132c565b5b141561082e576040518060400160405280600281526020017f213d0000000000000000000000000000000000000000000000000000000000008152509050610869565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108609061175e565b60405180910390fd5b919050565b60008163ffffffff16836000015163ffffffff1614156108915760019050610896565b600090505b92915050565b8280546108a89061138a565b90600052602060002090601f0160209004810192826108ca5760008555610911565b82601f106108e357805160ff1916838001178555610911565b82800160010185558215610911579182015b828111156109105782518255916020019190600101906108f5565b5b50905061091e919061093c565b5090565b604051806040016040528060608152602001606081525090565b5b8082111561095557600081600090555060010161093d565b5090565b6000604051905090565b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6109bb82610972565b810181811067ffffffffffffffff821117156109da576109d9610983565b5b80604052505050565b60006109ed610959565b90506109f982826109b2565b919050565b600067ffffffffffffffff821115610a1957610a18610983565b5b602082029050602081019050919050565b600080fd5b600080fd5b600080fd5b600063ffffffff82169050919050565b610a5281610a39565b8114610a5d57600080fd5b50565b600081359050610a6f81610a49565b92915050565b600080fd5b600067ffffffffffffffff821115610a9557610a94610983565b5b610a9e82610972565b9050602081019050919050565b82818337600083830152505050565b6000610acd610ac884610a7a565b6109e3565b905082815260208101848484011115610ae957610ae8610a75565b5b610af4848285610aab565b509392505050565b600082601f830112610b1157610b1061096d565b5b8135610b21848260208601610aba565b91505092915050565b600067ffffffffffffffff821115610b4557610b44610983565b5b602082029050602081019050919050565b6000610b69610b6484610b2a565b6109e3565b90508083825260208201905060208402830185811115610b8c57610b8b610a2a565b5b835b81811015610bb55780610ba18882610a60565b845260208401935050602081019050610b8e565b5050509392505050565b600082601f830112610bd457610bd361096d565b5b8135610be4848260208601610b56565b91505092915050565b600060608284031215610c0357610c02610a2f565b5b610c0d60606109e3565b90506000610c1d84828501610a60565b600083015250602082013567ffffffffffffffff811115610c4157610c40610a34565b5b610c4d84828501610afc565b602083015250604082013567ffffffffffffffff811115610c7157610c70610a34565b5b610c7d84828501610bbf565b60408301525092915050565b6000610c9c610c97846109fe565b6109e3565b90508083825260208201905060208402830185811115610cbf57610cbe610a2a565b5b835b81811015610d0657803567ffffffffffffffff811115610ce457610ce361096d565b5b808601610cf18982610bed565b85526020850194505050602081019050610cc1565b5050509392505050565b600082601f830112610d2557610d2461096d565b5b8135610d35848260208601610c89565b91505092915050565b600067ffffffffffffffff821115610d5957610d58610983565b5b602082029050602081019050919050565b600067ffffffffffffffff821115610d8557610d84610983565b5b610d8e82610972565b9050602081019050919050565b6000610dae610da984610d6a565b6109e3565b905082815260208101848484011115610dca57610dc9610a75565b5b610dd5848285610aab565b509392505050565b600082601f830112610df257610df161096d565b5b8135610e02848260208601610d9b565b91505092915050565b6000610e1e610e1984610d3e565b6109e3565b90508083825260208201905060208402830185811115610e4157610e40610a2a565b5b835b81811015610e8857803567ffffffffffffffff811115610e6657610e6561096d565b5b808601610e738982610ddd565b85526020850194505050602081019050610e43565b5050509392505050565b600082601f830112610ea757610ea661096d565b5b8135610eb7848260208601610e0b565b91505092915050565b600080600060608486031215610ed957610ed8610963565b5b600084013567ffffffffffffffff811115610ef757610ef6610968565b5b610f0386828701610d10565b935050602084013567ffffffffffffffff811115610f2457610f23610968565b5b610f3086828701610e92565b925050604084013567ffffffffffffffff811115610f5157610f50610968565b5b610f5d86828701610afc565b9150509250925092565b600081519050919050565b600082825260208201905092915050565b60005b83811015610fa1578082015181840152602081019050610f86565b83811115610fb0576000848401525b50505050565b6000610fc182610f67565b610fcb8185610f72565b9350610fdb818560208601610f83565b610fe481610972565b840191505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600082825260208201905092915050565b600061103782610f67565b611041818561101b565b9350611051818560208601610f83565b61105a81610972565b840191505092915050565b6000611071838361102c565b905092915050565b6000602082019050919050565b600061109182610fef565b61109b8185610ffa565b9350836020820285016110ad8561100b565b8060005b858110156110e957848403895281516110ca8582611065565b94506110d583611079565b925060208a019950506001810190506110b1565b50829750879550505050505092915050565b60008115159050919050565b611110816110fb565b82525050565b600060a08201905081810360008301526111308188610fb6565b905081810360208301526111448187610fb6565b905081810360408301526111588186611086565b9050818103606083015261116c8185610fb6565b905061117b6080830184611107565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081905092915050565b7f687474703a2f2f6c6f63616c686f73743a31393532372f6576656e74732f646f60008201527f65732d757365722d6a6f696e65642d65766d2d63616d706169676e3f6163636f60208201527f756e743d00000000000000000000000000000000000000000000000000000000604082015250565b60006112416044836111b4565b915061124c826111bf565b604482019050919050565b600061126282610f67565b61126c81856111b4565b935061127c818560208601610f83565b80840191505092915050565b600061129382611234565b915061129f8284611257565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000819050919050565b60006112ee826112d9565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611321576113206112aa565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806113a257607f821691505b602082108114156113b6576113b561135b565b5b50919050565b600081519050919050565b600082825260208201905092915050565b60006113e3826113bc565b6113ed81856113c7565b93506113fd818560208601610f83565b61140681610972565b840191505092915050565b6000602082019050818103600083015261142b81846113d8565b905092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000604083016000830151848203600086015261147c828261102c565b91505060208301518482036020860152611496828261102c565b9150508091505092915050565b60006114af838361145f565b905092915050565b6000602082019050919050565b60006114cf82611433565b6114d9818561143e565b9350836020820285016114eb8561144f565b8060005b85811015611527578484038952815161150885826114a3565b9450611513836114b7565b925060208a019950506001810190506114ef565b50829750879550505050505092915050565b600060608201905081810360008301526115538186610fb6565b905081810360208301526115678185610fb6565b9050818103604083015261157b81846114c4565b9050949350505050565b7f7b22737263223a22000000000000000000000000000000000000000000000000600082015250565b60006115bb6008836111b4565b91506115c682611585565b600882019050919050565b7f222c226f70223a22000000000000000000000000000000000000000000000000600082015250565b60006116076008836111b4565b9150611612826115d1565b600882019050919050565b7f222c22647374223a220000000000000000000000000000000000000000000000600082015250565b60006116536009836111b4565b915061165e8261161d565b600982019050919050565b7f227d000000000000000000000000000000000000000000000000000000000000600082015250565b600061169f6002836111b4565b91506116aa82611669565b600282019050919050565b60006116c0826115ae565b91506116cc8286611257565b91506116d7826115fa565b91506116e38285611257565b91506116ee82611646565b91506116fa8284611257565b915061170582611692565b9150819050949350505050565b7f556e737570706f72746564206f70657261746f72000000000000000000000000600082015250565b6000611748601483610f72565b915061175382611712565b602082019050919050565b600060208201905081810360008301526117778161173b565b905091905056fe68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f6c6974656e7472792f76632d6a736f6e736368656d612f6d61696e2f646973742f736368656d61732f31322d69646875622d65766d2d76657273696f6e2d6561726c792d626972642f312d302d302e6a736f6e546865207573657220697320616e206561726c7920626972642075736572206f6620746865204964656e746974794875622045564d2076657273696f6e20616e64206861732067656e657261746564206174206c6561737420312063726564656e7469616c20647572696e672032303233204175672031347468207e2041756720323173742ea26469706673582212209af1099598e181e18b4e56f879457e0cda71a0987588796c8d3806a0f349621464736f6c634300080b0033").unwrap(), + hex::decode("608060405234801561001057600080fd5b50611a02806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063b4e4c68514610030575b600080fd5b61004a60048036038101906100459190610f9b565b610064565b60405161005b9594939291906111f1565b60405180910390f35b60608060608060006100aa6040518060400160405280601981526020017f626567696e2067656e657261746520564320666f7220413230000000000000008152506104a3565b60006040518060c001604052806086815260200161194760869139905060006040518060400160405280601c81526020017f49444875622045564d2056657273696f6e204561726c7920426972640000000081525090506040518060a00160405280607581526020016118d2607591396000908051906020019061012f929190610977565b506000805b8b518110156102a1576101608c828151811061015357610152611260565b5b60200260200101516104b1565b1561028d5760008061018f8e848151811061017e5761017d611260565b5b6020026020010151602001516104e3565b91509150811561027d57816101a557505061028e565b6000816040516020016101b89190611363565b604051602081830303815290604052905060006040518060400160405280600a81526020017f2f6861734a6f696e656400000000000000000000000000000000000000000000815250905060008067ffffffffffffffff81111561021f5761021e610a5e565b5b60405190808252806020026020018201604052801561025857816020015b6102456109fd565b81526020019060019003908161023d5790505b509050600080610269858585610549565b915091508115610277578098505b50505050505b831561028a5750506102a1565b50505b5b8080610299906113be565b915050610134565b506102e06040518060400160405280601e81526020017f626567696e2063726561746520617373657274696f6e20666f722041323000008152506104a3565b600060405180606001604052806040518060400160405280600b81526020017f246861735f6a6f696e656400000000000000000000000000000000000000000081525081526020016004600581111561033c5761033b611407565b5b81526020016040518060400160405280600481526020017f747275650000000000000000000000000000000000000000000000000000000081525081525090506000600167ffffffffffffffff81111561039957610398610a5e565b5b6040519080825280602002602001820160405280156103cc57816020015b60608152602001906001900390816103b75790505b5090506103d8826105bf565b816000815181106103ec576103eb611260565b5b602002602001018190525084848260008681805461040990611465565b80601f016020809104026020016040519081016040528092919081815260200182805461043590611465565b80156104825780601f1061045757610100808354040283529160200191610482565b820191906000526020600020905b81548152906001019060200180831161046557829003601f168201915b50505050509150995099509950995099505050505050939792965093509350565b6104ae600182610600565b50565b60006104bc82610650565b806104cc57506104cb82610664565b5b806104dc57506104db82610678565b5b9050919050565b600060606000836040516020016104fa91906114ec565b6040516020818303038152906040529050600081519050604051611000818360208601600061041b600019f161052f57600080fd5b805194506040810193506110008101604052505050915091565b600080600080600087878760405160200161056693929190611614565b6040516020818303038152906040529050600081519050604051604081836020860160006103e9600019f161059a57600080fd5b8051945060208101519350604081016040525083839550955050505050935093915050565b606081600001516105d3836020015161068c565b83604001516040516020016105ea93929190611790565b6040516020818303038152906040529050919050565b60008282604051602001610615929190611835565b60405160208183030381529060405290506000815190506040516040818360208601600061041a600019f161064957600080fd5b5050505050565b600061065d826003610949565b9050919050565b6000610671826004610949565b9050919050565b6000610685826005610949565b9050919050565b6060600460058111156106a2576106a1611407565b5b8260058111156106b5576106b4611407565b5b14156106f8576040518060400160405280600281526020017f3d3d0000000000000000000000000000000000000000000000000000000000008152509050610944565b6000600581111561070c5761070b611407565b5b82600581111561071f5761071e611407565b5b1415610762576040518060400160405280600181526020017f3e000000000000000000000000000000000000000000000000000000000000008152509050610944565b6001600581111561077657610775611407565b5b82600581111561078957610788611407565b5b14156107cc576040518060400160405280600181526020017f3c000000000000000000000000000000000000000000000000000000000000008152509050610944565b600260058111156107e0576107df611407565b5b8260058111156107f3576107f2611407565b5b1415610836576040518060400160405280600281526020017f3e3d0000000000000000000000000000000000000000000000000000000000008152509050610944565b6003600581111561084a57610849611407565b5b82600581111561085d5761085c611407565b5b14156108a0576040518060400160405280600281526020017f3c3d0000000000000000000000000000000000000000000000000000000000008152509050610944565b6005808111156108b3576108b2611407565b5b8260058111156108c6576108c5611407565b5b1415610909576040518060400160405280600281526020017f213d0000000000000000000000000000000000000000000000000000000000008152509050610944565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093b906118b1565b60405180910390fd5b919050565b60008163ffffffff16836000015163ffffffff16141561096c5760019050610971565b600090505b92915050565b82805461098390611465565b90600052602060002090601f0160209004810192826109a557600085556109ec565b82601f106109be57805160ff19168380011785556109ec565b828001600101855582156109ec579182015b828111156109eb5782518255916020019190600101906109d0565b5b5090506109f99190610a17565b5090565b604051806040016040528060608152602001606081525090565b5b80821115610a30576000816000905550600101610a18565b5090565b6000604051905090565b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610a9682610a4d565b810181811067ffffffffffffffff82111715610ab557610ab4610a5e565b5b80604052505050565b6000610ac8610a34565b9050610ad48282610a8d565b919050565b600067ffffffffffffffff821115610af457610af3610a5e565b5b602082029050602081019050919050565b600080fd5b600080fd5b600080fd5b600063ffffffff82169050919050565b610b2d81610b14565b8114610b3857600080fd5b50565b600081359050610b4a81610b24565b92915050565b600080fd5b600067ffffffffffffffff821115610b7057610b6f610a5e565b5b610b7982610a4d565b9050602081019050919050565b82818337600083830152505050565b6000610ba8610ba384610b55565b610abe565b905082815260208101848484011115610bc457610bc3610b50565b5b610bcf848285610b86565b509392505050565b600082601f830112610bec57610beb610a48565b5b8135610bfc848260208601610b95565b91505092915050565b600067ffffffffffffffff821115610c2057610c1f610a5e565b5b602082029050602081019050919050565b6000610c44610c3f84610c05565b610abe565b90508083825260208201905060208402830185811115610c6757610c66610b05565b5b835b81811015610c905780610c7c8882610b3b565b845260208401935050602081019050610c69565b5050509392505050565b600082601f830112610caf57610cae610a48565b5b8135610cbf848260208601610c31565b91505092915050565b600060608284031215610cde57610cdd610b0a565b5b610ce86060610abe565b90506000610cf884828501610b3b565b600083015250602082013567ffffffffffffffff811115610d1c57610d1b610b0f565b5b610d2884828501610bd7565b602083015250604082013567ffffffffffffffff811115610d4c57610d4b610b0f565b5b610d5884828501610c9a565b60408301525092915050565b6000610d77610d7284610ad9565b610abe565b90508083825260208201905060208402830185811115610d9a57610d99610b05565b5b835b81811015610de157803567ffffffffffffffff811115610dbf57610dbe610a48565b5b808601610dcc8982610cc8565b85526020850194505050602081019050610d9c565b5050509392505050565b600082601f830112610e0057610dff610a48565b5b8135610e10848260208601610d64565b91505092915050565b600067ffffffffffffffff821115610e3457610e33610a5e565b5b602082029050602081019050919050565b600067ffffffffffffffff821115610e6057610e5f610a5e565b5b610e6982610a4d565b9050602081019050919050565b6000610e89610e8484610e45565b610abe565b905082815260208101848484011115610ea557610ea4610b50565b5b610eb0848285610b86565b509392505050565b600082601f830112610ecd57610ecc610a48565b5b8135610edd848260208601610e76565b91505092915050565b6000610ef9610ef484610e19565b610abe565b90508083825260208201905060208402830185811115610f1c57610f1b610b05565b5b835b81811015610f6357803567ffffffffffffffff811115610f4157610f40610a48565b5b808601610f4e8982610eb8565b85526020850194505050602081019050610f1e565b5050509392505050565b600082601f830112610f8257610f81610a48565b5b8135610f92848260208601610ee6565b91505092915050565b600080600060608486031215610fb457610fb3610a3e565b5b600084013567ffffffffffffffff811115610fd257610fd1610a43565b5b610fde86828701610deb565b935050602084013567ffffffffffffffff811115610fff57610ffe610a43565b5b61100b86828701610f6d565b925050604084013567ffffffffffffffff81111561102c5761102b610a43565b5b61103886828701610bd7565b9150509250925092565b600081519050919050565b600082825260208201905092915050565b60005b8381101561107c578082015181840152602081019050611061565b8381111561108b576000848401525b50505050565b600061109c82611042565b6110a6818561104d565b93506110b681856020860161105e565b6110bf81610a4d565b840191505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600082825260208201905092915050565b600061111282611042565b61111c81856110f6565b935061112c81856020860161105e565b61113581610a4d565b840191505092915050565b600061114c8383611107565b905092915050565b6000602082019050919050565b600061116c826110ca565b61117681856110d5565b935083602082028501611188856110e6565b8060005b858110156111c457848403895281516111a58582611140565b94506111b083611154565b925060208a0199505060018101905061118c565b50829750879550505050505092915050565b60008115159050919050565b6111eb816111d6565b82525050565b600060a082019050818103600083015261120b8188611091565b9050818103602083015261121f8187611091565b905081810360408301526112338186611161565b905081810360608301526112478185611091565b905061125660808301846111e2565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081905092915050565b7f687474703a2f2f6c6f63616c686f73743a31393532372f6576656e74732f646f60008201527f65732d757365722d6a6f696e65642d65766d2d63616d706169676e3f6163636f60208201527f756e743d00000000000000000000000000000000000000000000000000000000604082015250565b600061131c60448361128f565b91506113278261129a565b604482019050919050565b600061133d82611042565b611347818561128f565b935061135781856020860161105e565b80840191505092915050565b600061136e8261130f565b915061137a8284611332565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000819050919050565b60006113c9826113b4565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156113fc576113fb611385565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061147d57607f821691505b6020821081141561149157611490611436565b5b50919050565b600081519050919050565b600082825260208201905092915050565b60006114be82611497565b6114c881856114a2565b93506114d881856020860161105e565b6114e181610a4d565b840191505092915050565b6000602082019050818103600083015261150681846114b3565b905092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600060408301600083015184820360008601526115578282611107565b915050602083015184820360208601526115718282611107565b9150508091505092915050565b600061158a838361153a565b905092915050565b6000602082019050919050565b60006115aa8261150e565b6115b48185611519565b9350836020820285016115c68561152a565b8060005b8581101561160257848403895281516115e3858261157e565b94506115ee83611592565b925060208a019950506001810190506115ca565b50829750879550505050505092915050565b6000606082019050818103600083015261162e8186611091565b905081810360208301526116428185611091565b90508181036040830152611656818461159f565b9050949350505050565b7f7b22737263223a22000000000000000000000000000000000000000000000000600082015250565b600061169660088361128f565b91506116a182611660565b600882019050919050565b7f222c226f70223a22000000000000000000000000000000000000000000000000600082015250565b60006116e260088361128f565b91506116ed826116ac565b600882019050919050565b7f222c22647374223a220000000000000000000000000000000000000000000000600082015250565b600061172e60098361128f565b9150611739826116f8565b600982019050919050565b7f227d000000000000000000000000000000000000000000000000000000000000600082015250565b600061177a60028361128f565b915061178582611744565b600282019050919050565b600061179b82611689565b91506117a78286611332565b91506117b2826116d5565b91506117be8285611332565b91506117c982611721565b91506117d58284611332565b91506117e08261176d565b9150819050949350505050565b600581106117fe576117fd611407565b5b50565b600081905061180f826117ed565b919050565b600061181f82611801565b9050919050565b61182f81611814565b82525050565b600060408201905061184a6000830185611826565b818103602083015261185c8184611091565b90509392505050565b7f556e737570706f72746564206f70657261746f72000000000000000000000000600082015250565b600061189b60148361104d565b91506118a682611865565b602082019050919050565b600060208201905081810360008301526118ca8161188e565b905091905056fe68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f6c6974656e7472792f76632d6a736f6e736368656d612f6d61696e2f646973742f736368656d61732f31322d69646875622d65766d2d76657273696f6e2d6561726c792d626972642f312d302d302e6a736f6e546865207573657220697320616e206561726c7920626972642075736572206f6620746865204964656e746974794875622045564d2076657273696f6e20616e64206861732067656e657261746564206174206c6561737420312063726564656e7469616c20647572696e672032303233204175672031347468207e2041756720323173742ea26469706673582212200680df659706839637f9109cb11338bd6ac1080ede15ea24692cf77742bbee6964736f6c634300080b0033").unwrap(), vec![] ) ); diff --git a/tee-worker/litentry/core/common/src/platform_user/mod.rs b/tee-worker/litentry/core/common/src/platform_user/mod.rs index 3b35366042..657d7546bb 100644 --- a/tee-worker/litentry/core/common/src/platform_user/mod.rs +++ b/tee-worker/litentry/core/common/src/platform_user/mod.rs @@ -29,8 +29,9 @@ pub trait PlatformName { impl PlatformName for PlatformUserType { fn get_platform_name(&self) -> &'static str { match self { - Self::KaratDaoUser => "KaratDao", - Self::MagicCraftStakingUser => "MagicCraft", + Self::KaratDao => "KaratDao", + Self::MagicCraftStaking => "MagicCraft", + Self::DarenMarket => "DarenMarket", } } } diff --git a/tee-worker/litentry/core/common/src/web3_nft/mod.rs b/tee-worker/litentry/core/common/src/web3_nft/mod.rs index 3d48ae84e4..7c30ff57ee 100644 --- a/tee-worker/litentry/core/common/src/web3_nft/mod.rs +++ b/tee-worker/litentry/core/common/src/web3_nft/mod.rs @@ -33,6 +33,8 @@ impl NftName for Web3NftType { match self { Self::WeirdoGhostGang => "Weirdo Ghost Gang", Self::Club3Sbt => "Club3 SBT", + Self::MFan => "MFAN", + Self::Mvp => "MEME VIP PASS", } } } @@ -54,6 +56,12 @@ impl NftAddress for Web3NftType { Some("0xAc2e4e67cffa5E82bfA1e169e5F9aa405114C982"), (Self::Club3Sbt, Web3Network::Arbitrum) => Some("0xcccFF19FB8a4a2A206d07842b8F8c8c0A11904C2"), + // MFan + (Self::MFan, Web3Network::Polygon) => + Some("0x9aBc7C604C27622f9CD56bd1628F6321c32bBBf6"), + // Mvp + (Self::Mvp, Web3Network::Ethereum) => + Some("0xAA813F8691B10Dc62bd616ae90b05A52f0C40C1D"), _ => None, } } diff --git a/tee-worker/litentry/core/common/src/web3_token/mod.rs b/tee-worker/litentry/core/common/src/web3_token/mod.rs index 57513f464c..735f392c39 100644 --- a/tee-worker/litentry/core/common/src/web3_token/mod.rs +++ b/tee-worker/litentry/core/common/src/web3_token/mod.rs @@ -77,6 +77,8 @@ impl TokenName for Web3TokenType { Self::Cro => "CRO", Self::Inj => "INJ", Self::Bean => "BEAN", + Self::An => "AN", + Self::Tuna => "TUNA", } } } @@ -251,6 +253,13 @@ impl TokenAddress for Web3TokenType { (Self::Bean, Web3Network::Bsc) => Some("0x07da81e9a684ab87fad7206b3bc8d0866f48cc7c"), (Self::Bean, Web3Network::Combo) => Some("0xba7b9936a965fac23bb7a8190364fa60622b3cff"), + // An + (Self::An, Web3Network::Bsc) => Some("0x68d806380ce01e994f7583d796d0aea9ab470219"), + + // Tuna + (Self::Tuna, Web3Network::Ethereum) => + Some("0xadd353fb2e2c563383ff3272a500f3e7134dafe4"), + _ => None, } } @@ -327,6 +336,12 @@ impl TokenHoldingAmountRange for Web3TokenType { // Bean Self::Bean => BEAN_AMOUNT_RANGE.to_vec(), + // An + Self::An => AN_AMOUNT_RANGE.to_vec(), + + // Tuna + Self::Tuna => TUNA_AMOUNT_RANGE.to_vec(), + _ => [0.0, 1.0, 50.0, 100.0, 200.0, 500.0, 800.0, 1200.0, 1600.0, 3000.0].to_vec(), } } diff --git a/tee-worker/litentry/core/common/src/web3_token/token_amount_range.rs b/tee-worker/litentry/core/common/src/web3_token/token_amount_range.rs index e7b8055ae2..674f2380f5 100644 --- a/tee-worker/litentry/core/common/src/web3_token/token_amount_range.rs +++ b/tee-worker/litentry/core/common/src/web3_token/token_amount_range.rs @@ -49,3 +49,6 @@ pub const INJ_AMOUNT_RANGE: [f64; 6] = [0.0, 1.0, 5.0, 20.0, 50.0, 80.0]; pub const BTC_AMOUNT_RANGE: [f64; 14] = [0.0, 0.001, 0.1, 0.3, 0.6, 1.0, 2.0, 5.0, 10.0, 15.0, 25.0, 30.0, 40.0, 50.0]; pub const BEAN_AMOUNT_RANGE: [f64; 5] = [0.0, 1_500.0, 5_000.0, 10_000.0, 50_000.0]; +pub const AN_AMOUNT_RANGE: [f64; 7] = + [0.0, 100_000.0, 900_000.0, 1_800_000.0, 3_600_000.0, 7_200_000.0, 10_000_000.0]; +pub const TUNA_AMOUNT_RANGE: [f64; 7] = [0.0, 100.0, 1_000.0, 2_000.0, 4_000.0, 8_000.0, 12_000.0]; diff --git a/tee-worker/litentry/core/common/src/web3_token/token_decimals_filter.rs b/tee-worker/litentry/core/common/src/web3_token/token_decimals_filter.rs index d147db6993..33b070f8fa 100644 --- a/tee-worker/litentry/core/common/src/web3_token/token_decimals_filter.rs +++ b/tee-worker/litentry/core/common/src/web3_token/token_decimals_filter.rs @@ -83,7 +83,7 @@ pub const TOKEN_DECIMALS_9: (u32, [(Web3TokenType, Web3Network); 4]) = ( ], ); -pub const TOKEN_DECIMALS_18: (u32, [(Web3TokenType, Web3Network); 50]) = ( +pub const TOKEN_DECIMALS_18: (u32, [(Web3TokenType, Web3Network); 52]) = ( 18, [ // Bnb @@ -168,6 +168,10 @@ pub const TOKEN_DECIMALS_18: (u32, [(Web3TokenType, Web3Network); 50]) = ( // Bean (Web3TokenType::Bean, Web3Network::Bsc), (Web3TokenType::Bean, Web3Network::Combo), + // An + (Web3TokenType::An, Web3Network::Bsc), + // Tuna + (Web3TokenType::Tuna, Web3Network::Ethereum), ], ); diff --git a/tee-worker/litentry/core/credentials/src/credential_schema.rs b/tee-worker/litentry/core/credentials/src/credential_schema.rs index 0467414f25..be4d9019e1 100644 --- a/tee-worker/litentry/core/credentials/src/credential_schema.rs +++ b/tee-worker/litentry/core/credentials/src/credential_schema.rs @@ -107,12 +107,12 @@ pub fn get_schema_url(assertion: &Assertion) -> Option { Assertion::CryptoSummary => Some(format!("{BASE_URL}/23-crypto-summary/1-1-0.json")), - Assertion::PlatformUser(_) => Some(format!("{BASE_URL}/24-platform-user/1-1-1.json")), + Assertion::PlatformUser(_) => Some(format!("{BASE_URL}/24-platform-user/1-1-2.json")), - Assertion::NftHolder(_) => Some(format!("{BASE_URL}/26-nft-holder/1-1-0.json")), + Assertion::NftHolder(_) => Some(format!("{BASE_URL}/26-nft-holder/1-1-2.json")), Assertion::TokenHoldingAmount(_) => - Some(format!("{BASE_URL}/25-token-holding-amount/1-1-2.json")), + Some(format!("{BASE_URL}/25-token-holding-amount/1-1-3.json")), Assertion::Dynamic(..) => None, } diff --git a/tee-worker/litentry/core/data-providers/src/daren_market.rs b/tee-worker/litentry/core/data-providers/src/daren_market.rs new file mode 100644 index 0000000000..1da1f3880d --- /dev/null +++ b/tee-worker/litentry/core/data-providers/src/daren_market.rs @@ -0,0 +1,169 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +#[cfg(all(not(feature = "std"), feature = "sgx"))] +use crate::sgx_reexport_prelude::*; + +#[cfg(all(not(feature = "std"), feature = "sgx"))] +extern crate sgx_tstd as std; + +use crate::{ + build_client_with_cert, DataProviderConfig, Error, HttpError, ReqPath, RetryOption, + RetryableRestGet, +}; +use http::header::CONNECTION; +use http_req::response::Headers; +use itc_rest_client::{ + http_client::{HttpClient, SendWithCertificateVerification}, + rest_client::RestClient, + RestPath, +}; +use log::debug; +use serde::{Deserialize, Serialize}; +use std::{ + str, + string::{String, ToString}, + vec, + vec::Vec, +}; + +pub struct DarenMarketClient { + retry_option: RetryOption, + client: RestClient>, +} + +#[derive(Debug)] +pub struct DarenMarketRequest { + path: String, + query: Option>, +} + +impl DarenMarketClient { + pub fn new(data_provider_config: &DataProviderConfig) -> Self { + let api_retry_delay = data_provider_config.daren_market_api_retry_delay; + let api_retry_times = data_provider_config.daren_market_api_retry_times; + let api_url = data_provider_config.daren_market_api_url.clone(); + let retry_option = + RetryOption { retry_delay: Some(api_retry_delay), retry_times: Some(api_retry_times) }; + + let mut headers = Headers::new(); + headers.insert(CONNECTION.as_str(), "close"); + let client = build_client_with_cert(api_url.as_str(), headers); + + DarenMarketClient { retry_option, client } + } + + fn get(&mut self, params: DarenMarketRequest, fast_fail: bool) -> Result + where + T: serde::de::DeserializeOwned + for<'a> RestPath>, + { + let retry_option: Option = + if fast_fail { None } else { Some(self.retry_option.clone()) }; + if let Some(query) = params.query { + let transformed_query: Vec<(&str, &str)> = + query.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect(); + self.client.get_with_retry::( + ReqPath::new(params.path.as_str()), + &transformed_query, + retry_option, + ) + } else { + self.client + .get_retry::(ReqPath::new(params.path.as_str()), retry_option) + } + } +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct UserVerificationResponse { + pub success: bool, + pub created: bool, + pub message: String, +} + +impl<'a> RestPath> for UserVerificationResponse { + fn get_path(path: ReqPath) -> Result { + Ok(path.path.into()) + } +} + +pub trait DarenMarketApi { + fn user_verification( + &mut self, + address: String, + fail_fast: bool, + ) -> Result; +} + +impl DarenMarketApi for DarenMarketClient { + fn user_verification( + &mut self, + address: String, + fail_fast: bool, + ) -> Result { + let query: Vec<(String, String)> = vec![("address".to_string(), address)]; + + let params = DarenMarketRequest { path: "api/talent-asset".into(), query: Some(query) }; + + debug!("DarenMarket user_verification, params: {:?}", params); + + match self.get::(params, fail_fast) { + Ok(resp) => { + debug!("DarenMarket user_verification, response: {:?}", resp); + Ok(resp) + }, + Err(e) => { + debug!("DarenMarket user_verification, error: {:?}", e); + Err(e) + }, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use lc_mock_server::run; + + fn init() -> DataProviderConfig { + let _ = env_logger::builder().is_test(true).try_init(); + let url = run(0).unwrap() + "/daren_market/"; + + let mut config = DataProviderConfig::new().unwrap(); + config.set_daren_market_api_url(url).unwrap(); + config + } + + #[test] + fn does_user_verification_works() { + let config = init(); + let mut client = DarenMarketClient::new(&config); + let mut response = client + .user_verification("0x49ad262c49c7aa708cc2df262ed53b64a17dd5ee".into(), true) + .unwrap(); + assert_eq!(response.success, true); + assert_eq!(response.created, true); + assert_eq!(response.message, "Talent Asset Found!".to_string()); + + response = client + .user_verification("0x9401518f4ebba857baa879d9f76e1cc8b31ed197".into(), false) + .unwrap(); + assert_eq!(response.success, false); + assert_eq!(response.created, false); + assert_eq!(response.message, "".to_string()); + } +} diff --git a/tee-worker/litentry/core/data-providers/src/karat_dao.rs b/tee-worker/litentry/core/data-providers/src/karat_dao.rs index 0a0f6fedc0..e3d78bb83b 100644 --- a/tee-worker/litentry/core/data-providers/src/karat_dao.rs +++ b/tee-worker/litentry/core/data-providers/src/karat_dao.rs @@ -123,15 +123,15 @@ impl KaratDaoApi for KaratDaoClient { let params = KaratDaoRequest { path: "user/verification".into(), query: Some(query) }; - debug!("user_verification, params: {:?}", params); + debug!("KaratDao user_verification, params: {:?}", params); match self.get::(params, fail_fast) { Ok(resp) => { - debug!("user_verification, response: {:?}", resp); + debug!("KaratDao user_verification, response: {:?}", resp); Ok(resp) }, Err(e) => { - debug!("user_verification, error: {:?}", e); + debug!("KaratDao user_verification, error: {:?}", e); Err(e) }, } diff --git a/tee-worker/litentry/core/data-providers/src/lib.rs b/tee-worker/litentry/core/data-providers/src/lib.rs index b4a3af74e3..97eb91ce9c 100644 --- a/tee-worker/litentry/core/data-providers/src/lib.rs +++ b/tee-worker/litentry/core/data-providers/src/lib.rs @@ -64,6 +64,7 @@ compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the sam pub mod achainable; pub mod achainable_names; pub mod blockchain_info; +pub mod daren_market; pub mod discord_litentry; pub mod discord_official; pub mod geniidata; @@ -201,6 +202,9 @@ pub struct DataProviderConfig { pub magic_craft_api_retry_times: u16, pub magic_craft_api_url: String, pub magic_craft_api_key: String, + pub daren_market_api_retry_delay: u64, + pub daren_market_api_retry_times: u16, + pub daren_market_api_url: String, pub moralis_api_url: String, pub moralis_solana_api_url: String, pub moralis_api_retry_delay: u64, @@ -253,6 +257,9 @@ impl DataProviderConfig { magic_craft_api_retry_times: 2, magic_craft_api_url: "https://lobby-api-prod.magiccraft.io/".to_string(), magic_craft_api_key: "".to_string(), + daren_market_api_retry_delay: 5000, + daren_market_api_retry_times: 2, + daren_market_api_url: "https://daren.market/".to_string(), moralis_api_key: "".to_string(), moralis_api_retry_delay: 5000, moralis_api_retry_times: 2, @@ -338,6 +345,15 @@ impl DataProviderConfig { if let Ok(v) = env::var("MAGIC_CRAFT_API_URL") { config.set_magic_craft_api_url(v)?; } + if let Ok(v) = env::var("DAREN_MARKET_API_RETRY_DELAY") { + config.set_daren_market_api_retry_delay(v.parse::().unwrap()); + } + if let Ok(v) = env::var("DAREN_MARKET_API_RETRY_TIMES") { + config.set_daren_market_api_retry_times(v.parse::().unwrap()); + } + if let Ok(v) = env::var("DAREN_MARKET_API_URL") { + config.set_daren_market_api_url(v)?; + } if let Ok(v) = env::var("MORALIS_API_URL") { config.set_moralis_api_url(v)?; } @@ -563,6 +579,20 @@ impl DataProviderConfig { debug!("set_magic_craft_api_key: {:?}", v); self.magic_craft_api_key = v; } + pub fn set_daren_market_api_retry_delay(&mut self, v: u64) { + debug!("set_daren_market_api_retry_delay: {:?}", v); + self.daren_market_api_retry_delay = v; + } + pub fn set_daren_market_api_retry_times(&mut self, v: u16) { + debug!("set_daren_market_api_retry_times: {:?}", v); + self.daren_market_api_retry_times = v; + } + pub fn set_daren_market_api_url(&mut self, v: String) -> Result<(), Error> { + check_url(&v)?; + debug!("set_daren_market_api_url: {:?}", v); + self.daren_market_api_url = v; + Ok(()) + } pub fn set_moralis_api_key(&mut self, v: String) { debug!("set_moralis_api_key: {:?}", v); self.moralis_api_key = v; diff --git a/tee-worker/litentry/core/data-providers/src/magic_craft.rs b/tee-worker/litentry/core/data-providers/src/magic_craft.rs index 4b8bd28396..b959b04e02 100644 --- a/tee-worker/litentry/core/data-providers/src/magic_craft.rs +++ b/tee-worker/litentry/core/data-providers/src/magic_craft.rs @@ -119,15 +119,15 @@ impl MagicCraftApi for MagicCraftClient { let params = MagicCraftRequest { path: "litentry/user".into(), query: Some(query) }; - debug!("user_verification, params: {:?}", params); + debug!("MagicCraft user_verification, params: {:?}", params); match self.get::(params, fail_fast) { Ok(resp) => { - debug!("user_verification, response: {:?}", resp); + debug!("MagicCraft user_verification, response: {:?}", resp); Ok(resp) }, Err(e) => { - debug!("user_verification, error: {:?}", e); + debug!("MagicCraft user_verification, error: {:?}", e); Err(e) }, } diff --git a/tee-worker/litentry/core/data-providers/src/nodereal.rs b/tee-worker/litentry/core/data-providers/src/nodereal.rs index d976f56b52..bdda4d6754 100644 --- a/tee-worker/litentry/core/data-providers/src/nodereal.rs +++ b/tee-worker/litentry/core/data-providers/src/nodereal.rs @@ -151,6 +151,7 @@ impl DomainInfo { NaiveDateTime::parse_from_str(&self.expires, "%Y-%m-%dT%H:%M:%SZ").map_err(|e| { Error::Utf8Error(format!("Nodereal parse domain expires date error: {:?}", e)) })?; + #[allow(deprecated)] let expired: DateTime = DateTime::from_utc(expired, TzUtc); Ok(expired <= now) diff --git a/tee-worker/litentry/core/dynamic-assertion/src/lib.rs b/tee-worker/litentry/core/dynamic-assertion/src/lib.rs index 51726f4c99..8cf43f956e 100644 --- a/tee-worker/litentry/core/dynamic-assertion/src/lib.rs +++ b/tee-worker/litentry/core/dynamic-assertion/src/lib.rs @@ -41,6 +41,7 @@ pub struct AssertionResult { pub assertions: Vec, pub schema_url: String, pub meet: bool, + pub contract_logs: Vec, } pub trait AssertionExecutor { diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/.gitignore b/tee-worker/litentry/core/evm-dynamic-assertions/.gitignore new file mode 100644 index 0000000000..ce76fa023b --- /dev/null +++ b/tee-worker/litentry/core/evm-dynamic-assertions/.gitignore @@ -0,0 +1 @@ +!*.rs \ No newline at end of file diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/Cargo.toml b/tee-worker/litentry/core/evm-dynamic-assertions/Cargo.toml index cca4082a6b..eb0697f9e1 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/Cargo.toml +++ b/tee-worker/litentry/core/evm-dynamic-assertions/Cargo.toml @@ -10,6 +10,7 @@ edition = "2021" # std dependecies base58 = { version = "0.2", default-features = false } blake2-rfc = { version = "0.2.18", default-features = false } +chrono = { version = "0.4.26", default-features = true, optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } http = { version = "0.2", optional = true } rust_decimal = { version = "1.35.0", default-features = false } @@ -17,6 +18,7 @@ ss58-registry = { version = "1.40", default-features = false } thiserror = { version = "1.0.26", optional = true } # sgx dependencies +chrono_sgx = { package = "chrono", git = "https://github.com/mesalock-linux/chrono-sgx", optional = true } http-sgx = { package = "http", git = "https://github.com/integritee-network/http-sgx.git", branch = "sgx-experimental", optional = true } itp-sgx-temp-dir = { version = "0.1", default-features = false, path = "../../../core-primitives/sgx/temp-dir", optional = true } sgx_tstd = { branch = "master", git = "https://github.com/apache/teaclave-sgx-sdk.git", optional = true } @@ -52,6 +54,7 @@ std = [ "serde_json/std", "http", "thiserror", + "chrono", ] sgx = [ "sgx_tstd", @@ -60,5 +63,6 @@ sgx = [ "itc-rest-client/sgx", "itp-sgx-io/sgx", "thiserror-sgx", + "chrono_sgx", ] sgx-test = ["itp-sgx-temp-dir/sgx"] diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/lib.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/lib.rs index efdd32a483..6d7f9ab506 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/lib.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/lib.rs @@ -23,9 +23,13 @@ extern crate alloc; #[cfg(all(not(feature = "std"), feature = "sgx"))] extern crate sgx_tstd as std; +// #[cfg(all(not(feature = "std"), feature = "sgx"))] +// extern crate chrono_sgx as chrono; + // re-export module to properly feature gate sgx and regular std environment #[cfg(all(not(feature = "std"), feature = "sgx"))] pub mod sgx_reexport_prelude { + pub use chrono_sgx as chrono; pub use http_sgx as http; } @@ -70,7 +74,10 @@ pub struct EvmAssertionExecutor { pub assertion_repository: Arc, } -pub fn execute_smart_contract(byte_code: Vec, input_data: Vec) -> (ExitReason, Vec) { +pub fn execute_smart_contract( + byte_code: Vec, + input_data: Vec, +) -> (ExitReason, Vec, Vec) { // prepare EVM runtime let config = prepare_config(); let vicinity = prepare_memory(); @@ -78,7 +85,7 @@ pub fn execute_smart_contract(byte_code: Vec, input_data: Vec) -> (ExitR let mut backend = MemoryBackend::new(&vicinity, state); let metadata = StackSubstateMetadata::new(u64::MAX, &config); let state = MemoryStackState::new(metadata, &mut backend); - let precompiles = Precompiles {}; + let precompiles = Precompiles { contract_logs: Vec::new().into() }; let mut executor = StackExecutor::new_with_precompiles(state, &config, &precompiles); // caller, just an unused account @@ -90,7 +97,10 @@ pub fn execute_smart_contract(byte_code: Vec, input_data: Vec) -> (ExitR executor.transact_create(caller, U256::zero(), byte_code, u64::MAX, Vec::new()); // call assertion smart contract - executor.transact_call(caller, address, U256::zero(), input_data, u64::MAX, Vec::new()) + let (reason, data) = + executor.transact_call(caller, address, U256::zero(), input_data, u64::MAX, Vec::new()); + + (reason, data, precompiles.contract_logs.take()) } impl> @@ -117,7 +127,14 @@ impl> decode_result(&call_result.1) .map_err(|_| "Could not decode evm assertion execution result")?; - Ok(AssertionResult { description, assertion_type, assertions, schema_url, meet }) + Ok(AssertionResult { + description, + assertion_type, + assertions, + schema_url, + meet, + contract_logs: call_result.2, + }) } else { Err(std::format!("Fail to execution evm dynamic assertion: {:?}", call_result.0)) } diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/hex_to_number.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/hex_to_number.rs index 2977d3583e..e0ed3a8e57 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/hex_to_number.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/hex_to_number.rs @@ -113,7 +113,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code.clone(), input_data); + let (_, return_data, _) = execute_smart_contract(byte_code.clone(), input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -129,7 +129,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code.clone(), input_data); + let (_, return_data, _) = execute_smart_contract(byte_code.clone(), input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -151,7 +151,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code.clone(), input_data); + let (_, return_data, _) = execute_smart_contract(byte_code.clone(), input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/http_get.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/http_get.rs index c18cc2603b..13e362d545 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/http_get.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/http_get.rs @@ -256,7 +256,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -283,7 +283,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -318,7 +318,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -338,7 +338,7 @@ pub mod integration_test { Token::String("/hasJoined".to_string())])).unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -357,7 +357,7 @@ pub mod integration_test { Token::String("/hasJoined".to_string())])).unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -387,7 +387,7 @@ pub mod integration_test { ).unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -415,7 +415,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -441,7 +441,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -475,7 +475,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -497,7 +497,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -524,7 +524,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -550,7 +550,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/http_post.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/http_post.rs index 6897471d6f..712e6f45c2 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/http_post.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/http_post.rs @@ -215,7 +215,7 @@ pub mod integration_test { Token::String("/runningCost".to_string()), Token::String(r#"{"name": "Account total transactions under {amount}", "address": "test", "params": {"chain": "ChainName"}, "includeMetadata": false }"#.to_string()) ])).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::Int(2)]; // when @@ -237,7 +237,7 @@ pub mod integration_test { Token::String("/runningCost".to_string()), Token::String(r#"{"name": "Account total transactions under {amount}", "address": "test", "params": {"chain": "ChainName"}, "includeMetadata": false }"#.to_string()) ])).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::Int(2)]; // when @@ -267,7 +267,7 @@ pub mod integration_test { ] ) ).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::Int(2)]; // when @@ -291,7 +291,7 @@ pub mod integration_test { Token::String("/result".to_string()), Token::String(r#"{"name": "Account total transactions under {amount}", "address": "test", "params": {"chain": "ChainName"}, "includeMetadata": false }"#.to_string()) ])).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::Bool]; // when @@ -313,7 +313,7 @@ pub mod integration_test { Token::String("/result".to_string()), Token::String(r#"{"name": "Account total transactions under {amount}", "address": "test", "params": {"chain": "ChainName"}, "includeMetadata": false }"#.to_string()) ])).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::Bool]; // when @@ -343,7 +343,7 @@ pub mod integration_test { ] ) ).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::Bool]; // when @@ -367,7 +367,7 @@ pub mod integration_test { Token::String("/display/0/text".to_string()), Token::String(r#"{"name": "Account total transactions under {amount}", "address": "test", "params": {"chain": "ChainName"}, "includeMetadata": false }"#.to_string()) ])).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::String]; // when @@ -392,7 +392,7 @@ pub mod integration_test { Token::String("/display/0/text".to_string()), Token::String(r#"{"name": "Account total transactions under {amount}", "address": "test", "params": {"chain": "ChainName"}, "includeMetadata": false }"#.to_string()) ])).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::String]; // when @@ -422,7 +422,7 @@ pub mod integration_test { ] ) ).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::String]; // when @@ -447,7 +447,7 @@ pub mod integration_test { Token::String(format!("{}/v1/run/system-labels", url)), Token::String(r#"{"name": "Account total transactions under {amount}", "address": "test", "params": {"chain": "ChainName"}, "includeMetadata": false }"#.to_string()) ])).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::String]; let expected_value: Value = serde_json::from_str("{\"result\":true,\"display\":[{\"text\":\"Total transactions under 1 (Transactions: 41)\",\"result\":true}],\"runningCost\":1}").unwrap(); @@ -473,7 +473,7 @@ pub mod integration_test { Token::String("http://localhost:1/v1/run/system-labels".to_string()), Token::String(r#"{"name": "Account total transactions under {amount}", "address": "test", "params": {"chain": "ChainName"}, "includeMetadata": false }"#.to_string()) ])).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::String]; // when @@ -500,7 +500,7 @@ pub mod integration_test { ] ) ).unwrap(); - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); let types = vec![ethabi::ParamType::Bool, ethabi::ParamType::String]; let expected_value: Value = serde_json::from_str("{\"result\":true,\"display\":[{\"text\":\"Total transactions under 1 (Transactions: 41)\",\"result\":true}],\"runningCost\":1}").unwrap(); diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/identity_to_string.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/identity_to_string.rs index f9a9f7b6ca..8dc074f220 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/identity_to_string.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/identity_to_string.rs @@ -17,7 +17,9 @@ use crate::{failure_precompile_output, precompiles::PrecompileResult, success_precompile_output}; use base58::ToBase58; use blake2_rfc::blake2b::Blake2b; -use litentry_primitives::{p2pkh_address, p2sh_address, p2tr_address, p2wpkh_address, Web3Network}; +use litentry_primitives::{ + p2pkh_address, p2sh_address, p2tr_address, p2wpkh_address, p2wsh_address, Web3Network, +}; use ss58_registry::Ss58AddressFormat; use std::{format, string::String, vec, vec::Vec}; @@ -133,7 +135,9 @@ fn pubkey_to_address(network: u8, pubkey: &str) -> String { 11 => p2sh_address(pubkey), // BitcoinP2wpkh 12 => p2wpkh_address(pubkey), - // BitcoinP2wsh and others + // BitcoinP2wsh + 13 => p2wsh_address(pubkey), + // others _ => "".into(), } } @@ -228,6 +232,23 @@ pub mod test { )), result ); + + // BitcoinP2wsh + let encoded = encode(&[ + Token::Uint(Web3Network::BitcoinP2wsh.get_code().into()), + Token::Bytes(decode_hex(address.as_bytes().to_vec()).unwrap()), + ]); + + // when + let result = identity_to_string(encoded).unwrap(); + + // then + assert_eq!( + success_precompile_output(Token::String( + "bc1qvr0n2tgcevl26kx0vu76nujlju6fwkdzllv7qx5pz5ed3y8yf22st9hqmw".into() + )), + result + ); } #[test] @@ -297,7 +318,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code.clone(), input_data); + let (_, return_data, _) = execute_smart_contract(byte_code.clone(), input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -334,7 +355,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code.clone(), input_data); + let (_, return_data, _) = execute_smart_contract(byte_code.clone(), input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -358,7 +379,7 @@ pub mod integration_test { ]), ) .unwrap(); - let (_, return_data) = execute_smart_contract(byte_code.clone(), input_data); + let (_, return_data, _) = execute_smart_contract(byte_code.clone(), input_data); // when let decoded = decode(&return_types, &return_data).unwrap(); @@ -388,7 +409,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code.clone(), input_data); + let (_, return_data, _) = execute_smart_contract(byte_code.clone(), input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/json_utils.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/json_utils.rs index e8f8a62ab6..89a7b2b97f 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/json_utils.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/json_utils.rs @@ -1,6 +1,10 @@ use crate::{ - failure_precompile_output, json_get_fn, precompiles::PrecompileResult, - success_precompile_output, + failure_precompile_output, json_get_fn, + precompiles::{ + logging::{contract_logging, LOGGING_LEVEL_WARN}, + PrecompileResult, + }, + success_precompile_output, Precompiles, }; use ethabi::Token; use serde_json::Value; @@ -10,12 +14,14 @@ json_get_fn!(json_get_string, String, as_str); json_get_fn!(json_get_bool, Bool, as_bool); json_get_fn!(json_get_i64, Uint, as_i64); -pub fn get_array_len(input: Vec) -> PrecompileResult { +pub fn get_array_len(input: Vec, precompiles: &Precompiles) -> PrecompileResult { let decoded = match ethabi::decode(&[ethabi::ParamType::String, ethabi::ParamType::String], &input) { Ok(d) => d, Err(e) => { - log::debug!("Could not decode bytes {:?}, reason: {:?}", input, e); + let message = std::format!("Could not decode bytes {:?}, reason: {:?}", input, e); + log::debug!("{}", message); + contract_logging(precompiles, LOGGING_LEVEL_WARN, message); return Ok(failure_precompile_output(ethabi::Token::String(Default::default()))) }, }; @@ -26,7 +32,9 @@ pub fn get_array_len(input: Vec) -> PrecompileResult { let value: Value = match serde_json::from_str(&json) { Ok(v) => v, Err(e) => { - log::debug!("Could not parse json {:?}, reason: {:?}", json, e); + let message = std::format!("Could not parse json {:?}, reason: {:?}", json, e); + log::debug!("{}", message); + contract_logging(precompiles, LOGGING_LEVEL_WARN, message); return Ok(failure_precompile_output(Token::Int(Default::default()))) }, }; @@ -35,15 +43,19 @@ pub fn get_array_len(input: Vec) -> PrecompileResult { Some(v) => match v.as_array() { Some(arr) => arr.len(), None => { - log::debug!( + let message = std::format!( "There is no value or it might be of different type, pointer: ${:?}", pointer ); + log::debug!("{}", message); + contract_logging(precompiles, LOGGING_LEVEL_WARN, message); return Ok(failure_precompile_output(Token::Int(Default::default()))) }, }, None => { - log::debug!("No value under given pointer: :{:?}", pointer); + let message = std::format!("No value under given pointer: :{:?}", pointer); + log::debug!("{}", message); + contract_logging(precompiles, LOGGING_LEVEL_WARN, message); return Ok(failure_precompile_output(Token::Int(Default::default()))) }, }; @@ -55,7 +67,7 @@ pub fn get_array_len(input: Vec) -> PrecompileResult { pub mod test { use crate::{ precompiles::json_utils::{get_array_len, json_get_bool, json_get_i64, json_get_string}, - success_precompile_output, + success_precompile_output, Precompiles, }; use ethabi::{encode, Token}; use serde_json::json; @@ -71,7 +83,8 @@ pub mod test { let data = prepare_input_data(&json.to_string(), "/key"); // when: - let result = json_get_string(data).unwrap(); + let precompiles = Precompiles { contract_logs: Vec::new().into() }; + let result = json_get_string(data, &precompiles).unwrap(); // then assert_eq!(success_precompile_output(Token::String("value".into())), result) @@ -88,7 +101,8 @@ pub mod test { let data = prepare_input_data(&json.to_string(), "/key"); // when: - let result = json_get_i64(data).unwrap(); + let precompiles = Precompiles { contract_logs: Vec::new().into() }; + let result = json_get_i64(data, &precompiles).unwrap(); // then assert_eq!(success_precompile_output(Token::Int(14.into())), result) @@ -105,7 +119,8 @@ pub mod test { let data = prepare_input_data(&json.to_string(), "/key"); // when: - let result = json_get_bool(data).unwrap(); + let precompiles = Precompiles { contract_logs: Vec::new().into() }; + let result = json_get_bool(data, &precompiles).unwrap(); // then assert_eq!(success_precompile_output(Token::Bool(true)), result) @@ -118,7 +133,8 @@ pub mod test { let data = prepare_input_data(&json.to_string(), ""); // when: - let result = get_array_len(data).unwrap(); + let precompiles = Precompiles { contract_logs: Vec::new().into() }; + let result = get_array_len(data, &precompiles).unwrap(); // then assert_eq!(success_precompile_output(Token::Int(3.into())), result) @@ -137,7 +153,8 @@ pub mod test { let data = prepare_input_data(&json.to_string(), "/nested"); // when: - let result = get_array_len(data).unwrap(); + let precompiles = Precompiles { contract_logs: Vec::new().into() }; + let result = get_array_len(data, &precompiles).unwrap(); // then assert_eq!(success_precompile_output(Token::Int(3.into())), result) @@ -182,7 +199,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -211,7 +228,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -240,7 +257,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -273,7 +290,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/logging.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/logging.rs new file mode 100644 index 0000000000..dda1c5093f --- /dev/null +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/logging.rs @@ -0,0 +1,230 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +use crate::{ + failure_precompile_output, precompiles::PrecompileResult, success_precompile_output, + Precompiles, +}; + +#[cfg(all(not(feature = "std"), feature = "sgx"))] +use crate::sgx_reexport_prelude::chrono::{ + offset::Utc as TzUtc, DateTime, NaiveDateTime, SecondsFormat, +}; + +#[cfg(all(not(feature = "std"), feature = "sgx"))] +use std::time::{SystemTime, UNIX_EPOCH}; + +#[cfg(feature = "std")] +use chrono::{offset::Utc as TzUtc, DateTime, SecondsFormat}; + +use std::{format, string::String, vec::Vec}; + +pub const LOGGING_LEVEL_DEBUG: u8 = 0; +#[allow(dead_code)] +pub const LOGGING_LEVEL_INFO: u8 = 1; +pub const LOGGING_LEVEL_WARN: u8 = 2; +pub const LOGGING_LEVEL_ERROR: u8 = 3; +pub const LOGGING_LEVEL_FATAL: u8 = 4; + +pub fn logging(input: Vec, precompiles: &Precompiles) -> PrecompileResult { + let decoded = + match ethabi::decode(&[ethabi::ParamType::Uint(8), ethabi::ParamType::String], &input) { + Ok(d) => d, + Err(e) => { + log::debug!("Could not decode input {:?}, reason: {:?}", input, e); + return Ok(failure_precompile_output(ethabi::Token::Bool(Default::default()))) + }, + }; + let level = match decoded.get(0).and_then(|v| v.clone().into_uint()) { + Some(v) => v, + None => { + log::debug!("Could not convert decoded[0] to uint"); + return Ok(failure_precompile_output(ethabi::Token::Bool(Default::default()))) + }, + } + .as_u32() as u8; + let message = match decoded.get(1).and_then(|v| v.clone().into_string()) { + Some(v) => v, + None => { + log::debug!("Could not convert decoded[1] to string"); + return Ok(failure_precompile_output(ethabi::Token::Bool(Default::default()))) + }, + }; + + contract_logging(precompiles, level, message); + + Ok(success_precompile_output(ethabi::Token::Bool(true))) +} + +pub fn contract_logging(precompiles: &Precompiles, level: u8, message: String) { + precompiles.contract_logs.borrow_mut().push(format!( + "[{} {}] {}", + now().to_rfc3339_opts(SecondsFormat::Micros, true), + loggin_level_to_string(level), + message + )); +} + +fn loggin_level_to_string(level: u8) -> String { + match level { + LOGGING_LEVEL_DEBUG => "DEBUG", + LOGGING_LEVEL_WARN => "WARN", + LOGGING_LEVEL_ERROR => "ERROR", + LOGGING_LEVEL_FATAL => "FATAL", + _ => "INFO", + } + .into() +} + +fn now() -> DateTime { + #[cfg(feature = "std")] + { + TzUtc::now() + } + + #[cfg(all(not(feature = "std"), feature = "sgx"))] + { + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time before Unix epoch"); + let naive = + NaiveDateTime::from_timestamp_opt(now.as_secs() as i64, now.subsec_nanos() as u32) + .unwrap(); + + DateTime::from_utc(naive, TzUtc) + } +} + +#[cfg(test)] +pub mod test { + use crate::{ + failure_precompile_output, + precompiles::logging::{logging, LOGGING_LEVEL_INFO}, + success_precompile_output, Precompiles, + }; + use ethabi::{encode, Token}; + + #[test] + pub fn test_logging() { + // given + let encoded = encode(&[ + Token::Uint(LOGGING_LEVEL_INFO.into()), + Token::String("This is an info message".into()), + ]); + + // when + let precompiles = Precompiles { contract_logs: Vec::new().into() }; + let result = logging(encoded, &precompiles).unwrap(); + + // then + assert_eq!(success_precompile_output(Token::Bool(true)), result); + assert_eq!(precompiles.contract_logs.borrow_mut().len(), 1); + } + + #[test] + pub fn test_logging_fail() { + // given + let encoded = encode(&[Token::String("This is an info message".into())]); + + // when + let precompiles = Precompiles { contract_logs: Vec::new().into() }; + let result = logging(encoded, &precompiles).unwrap(); + + // then + assert_eq!(failure_precompile_output(Token::Bool(Default::default())), result); + assert_eq!(precompiles.contract_logs.borrow_mut().len(), 0); + } +} + +#[cfg(test)] +pub mod integration_test { + use crate::{execute_smart_contract, precompiles::logging::*, prepare_function_call_input}; + use ethabi::{encode, Token}; + + // tee-worker/litentry/core/assertion-build/src/dynamic/contracts/tests/Logging.sol + const FUNCTION_HASH: &str = "a5c89545"; // callLogging(uint8,string) + const BYTE_CODE: &str = "608060405234801561001057600080fd5b50610413806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a5c8954514610030575b600080fd5b61004a60048036038101906100459190610252565b61004c565b005b61006b8260ff166004811115610065576100646102ae565b5b8261006f565b5050565b600082826040516020016100849291906103ad565b60405160208183030381529060405290506000815190506040516040818360208601600061041a600019f16100b857600080fd5b5050505050565b6000604051905090565b600080fd5b600080fd5b600060ff82169050919050565b6100e9816100d3565b81146100f457600080fd5b50565b600081359050610106816100e0565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61015f82610116565b810181811067ffffffffffffffff8211171561017e5761017d610127565b5b80604052505050565b60006101916100bf565b905061019d8282610156565b919050565b600067ffffffffffffffff8211156101bd576101bc610127565b5b6101c682610116565b9050602081019050919050565b82818337600083830152505050565b60006101f56101f0846101a2565b610187565b90508281526020810184848401111561021157610210610111565b5b61021c8482856101d3565b509392505050565b600082601f8301126102395761023861010c565b5b81356102498482602086016101e2565b91505092915050565b60008060408385031215610269576102686100c9565b5b6000610277858286016100f7565b925050602083013567ffffffffffffffff811115610298576102976100ce565b5b6102a485828601610224565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106102ee576102ed6102ae565b5b50565b60008190506102ff826102dd565b919050565b600061030f826102f1565b9050919050565b61031f81610304565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561035f578082015181840152602081019050610344565b8381111561036e576000848401525b50505050565b600061037f82610325565b6103898185610330565b9350610399818560208601610341565b6103a281610116565b840191505092915050565b60006040820190506103c26000830185610316565b81810360208301526103d48184610374565b9050939250505056fea264697066735822122013f32e65e5c8e0d8c134673c0a6f6cf67ba2acb957c1c6b87b4580b4f182777f64736f6c634300080b0033"; + + #[test] + pub fn test_logging() { + let byte_code = hex::decode(BYTE_CODE).unwrap(); + + let result = execute_smart_contract( + byte_code.clone(), + prepare_function_call_input( + FUNCTION_HASH, + encode(&[ + Token::Uint(LOGGING_LEVEL_DEBUG.into()), + Token::String("This is a debug message".to_string()), + ]), + ) + .unwrap(), + ); + assert_eq!(&result.2[0][29..], "DEBUG] This is a debug message"); + + let result = execute_smart_contract( + byte_code.clone(), + prepare_function_call_input( + FUNCTION_HASH, + encode(&[ + Token::Uint(LOGGING_LEVEL_INFO.into()), + Token::String("This is an info message".to_string()), + ]), + ) + .unwrap(), + ); + assert_eq!(&result.2[0][29..], "INFO] This is an info message"); + + let result = execute_smart_contract( + byte_code.clone(), + prepare_function_call_input( + FUNCTION_HASH, + encode(&[ + Token::Uint(LOGGING_LEVEL_WARN.into()), + Token::String("This is a warn message".to_string()), + ]), + ) + .unwrap(), + ); + assert_eq!(&result.2[0][29..], "WARN] This is a warn message"); + + let result = execute_smart_contract( + byte_code.clone(), + prepare_function_call_input( + FUNCTION_HASH, + encode(&[ + Token::Uint(LOGGING_LEVEL_ERROR.into()), + Token::String("This is a error message".to_string()), + ]), + ) + .unwrap(), + ); + assert_eq!(&result.2[0][29..], "ERROR] This is a error message"); + + let result = execute_smart_contract( + byte_code, + prepare_function_call_input( + FUNCTION_HASH, + encode(&[ + Token::Uint(LOGGING_LEVEL_FATAL.into()), + Token::String("This is a fatal message".to_string()), + ]), + ) + .unwrap(), + ); + assert_eq!(&result.2[0][29..], "FATAL] This is a fatal message"); + } +} diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/macros.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/macros.rs index 13b9e636c0..95e434b15a 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/macros.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/macros.rs @@ -19,14 +19,16 @@ use itc_rest_client::http_client::SendHttpRequest; #[macro_export] macro_rules! json_get_fn { ($name:ident, $token:ident, $parse_fn_name:ident) => { - pub fn $name(input: Vec) -> $crate::precompiles::PrecompileResult { + pub fn $name(input: Vec, precompiles: &Precompiles) -> $crate::precompiles::PrecompileResult { let decoded = match ethabi::decode( &[ethabi::ParamType::String, ethabi::ParamType::String], &input, ) { Ok(d) => d, Err(e) => { - log::debug!("Could not decode bytes {:?}, reason: {:?}", input, e); + let message = std::format!("Could not decode bytes {:?}, reason: {:?}", input, e); + log::debug!("{}", message); + contract_logging(precompiles, LOGGING_LEVEL_WARN, message); return Ok(failure_precompile_output(ethabi::Token::$token(Default::default()))) }, }; @@ -37,14 +39,18 @@ macro_rules! json_get_fn { let value: serde_json::Value = match serde_json::from_str(&json) { Ok(v) => v, Err(e) => { - log::debug!("Could not parse json {:?}, reason: {:?}", json, e); + let message = std::format!("Could not parse json {:?}, reason: {:?}", json, e); + log::debug!("{}", message); + contract_logging(precompiles, LOGGING_LEVEL_WARN, message); return Ok(failure_precompile_output(ethabi::Token::$token(Default::default()))) }, }; let result = match value.pointer(&pointer) { Some(v) => v, None => { - log::debug!("No value under given pointer: :{:?}", pointer); + let message = std::format!("No value under given pointer: :{:?}", pointer); + log::debug!("{}", message); + contract_logging(precompiles, LOGGING_LEVEL_WARN, message); return Ok(failure_precompile_output(ethabi::Token::$token(Default::default()))) }, }; @@ -52,10 +58,12 @@ macro_rules! json_get_fn { let encoded = match result.$parse_fn_name() { Some(v) => ethabi::Token::$token(v.into()), None => { - log::debug!( + let message = std::format!( "There is no value or it might be of different type, pointer: ${:?}", pointer ); + log::debug!("{}", message); + contract_logging(precompiles, LOGGING_LEVEL_WARN, message); return Ok(failure_precompile_output(ethabi::Token::$token(Default::default()))) }, }; diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/mod.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/mod.rs index 34498168c8..032ea571c0 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/mod.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/mod.rs @@ -25,6 +25,7 @@ use crate::precompiles::{ http_get::{http_get, http_get_bool, http_get_i64, http_get_string}, http_post::{http_post, http_post_bool, http_post_i64, http_post_string}, identity_to_string::identity_to_string, + logging::logging, parse_decimal::parse_decimal, parse_int::parse_int, to_hex::to_hex, @@ -34,13 +35,14 @@ use evm::executor::stack::{ IsPrecompileResult, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileSet, }; use itc_rest_client::http_client::HttpClient; -use std::result::Result as StdResult; +use std::{cell::RefCell, result::Result as StdResult, string::String, vec::Vec}; mod hex_to_number; mod http_get; mod http_post; mod identity_to_string; mod json_utils; +mod logging; mod macros; mod parse_decimal; mod parse_int; @@ -51,7 +53,9 @@ mod mocks; pub type PrecompileResult = StdResult; -pub struct Precompiles(); +pub struct Precompiles { + pub contract_logs: RefCell>, +} impl PrecompileSet for Precompiles { fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { @@ -74,15 +78,17 @@ impl PrecompileSet for Precompiles { a if a == hash(1005) => Some(http_post_string(handle.input().to_vec(), client)), a if a == hash(1006) => Some(http_get(handle.input().to_vec(), client)), a if a == hash(1007) => Some(http_post(handle.input().to_vec(), client)), + a if a == hash(1050) => Some(logging(handle.input().to_vec(), self)), a if a == hash(1051) => Some(to_hex(handle.input().to_vec())), a if a == hash(1052) => Some(identity_to_string(handle.input().to_vec())), a if a == hash(1053) => Some(hex_to_number(handle.input().to_vec())), a if a == hash(1054) => Some(parse_decimal(handle.input().to_vec())), a if a == hash(1055) => Some(parse_int(handle.input().to_vec())), - a if a == hash(1100) => Some(json_utils::json_get_string(handle.input().to_vec())), - a if a == hash(1101) => Some(json_utils::json_get_i64(handle.input().to_vec())), - a if a == hash(1102) => Some(json_utils::json_get_bool(handle.input().to_vec())), - a if a == hash(1103) => Some(json_utils::get_array_len(handle.input().to_vec())), + a if a == hash(1100) => + Some(json_utils::json_get_string(handle.input().to_vec(), self)), + a if a == hash(1101) => Some(json_utils::json_get_i64(handle.input().to_vec(), self)), + a if a == hash(1102) => Some(json_utils::json_get_bool(handle.input().to_vec(), self)), + a if a == hash(1103) => Some(json_utils::get_array_len(handle.input().to_vec(), self)), _ => None, } } @@ -105,6 +111,8 @@ impl PrecompileSet for Precompiles { IsPrecompileResult::Answer { is_precompile: true, extra_cost: 0 }, a if a == hash(1007) => IsPrecompileResult::Answer { is_precompile: true, extra_cost: 0 }, + a if a == hash(1050) => + IsPrecompileResult::Answer { is_precompile: true, extra_cost: 0 }, a if a == hash(1051) => IsPrecompileResult::Answer { is_precompile: true, extra_cost: 0 }, a if a == hash(1052) => diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/parse_decimal.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/parse_decimal.rs index 1717a18028..93907307af 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/parse_decimal.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/parse_decimal.rs @@ -129,7 +129,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code.clone(), input_data); + let (_, return_data, _) = execute_smart_contract(byte_code.clone(), input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -151,7 +151,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code.clone(), input_data); + let (_, return_data, _) = execute_smart_contract(byte_code.clone(), input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/parse_int.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/parse_int.rs index 1b097632c6..1a889e0bf6 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/parse_int.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/parse_int.rs @@ -100,7 +100,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code.clone(), input_data); + let (_, return_data, _) = execute_smart_contract(byte_code.clone(), input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); @@ -122,7 +122,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code.clone(), input_data); + let (_, return_data, _) = execute_smart_contract(byte_code.clone(), input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/to_hex.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/to_hex.rs index 52a2e2f048..f799345109 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/to_hex.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/precompiles/to_hex.rs @@ -91,7 +91,7 @@ pub mod integration_test { .unwrap(); // when - let (_, return_data) = execute_smart_contract(byte_code, input_data); + let (_, return_data, _) = execute_smart_contract(byte_code, input_data); // then let decoded = decode(&return_types, &return_data).unwrap(); diff --git a/tee-worker/litentry/core/evm-dynamic-assertions/src/repository.rs b/tee-worker/litentry/core/evm-dynamic-assertions/src/repository.rs index 23326f5da1..0a73227878 100644 --- a/tee-worker/litentry/core/evm-dynamic-assertions/src/repository.rs +++ b/tee-worker/litentry/core/evm-dynamic-assertions/src/repository.rs @@ -104,7 +104,7 @@ pub mod sgx_tests { use ethabi::ethereum_types::H160; use itp_sgx_temp_dir::TempDir; use lc_dynamic_assertion::AssertionLogicRepository; - use sgx_tstd::{path::Path, string::ToString, vec, vec::Vec}; + use sgx_tstd::{string::ToString, vec, vec::Vec}; pub fn restores_state_from_seal() { let seal_file_name = "test_sealed_assertion.bin"; diff --git a/tee-worker/litentry/core/mock-server/src/daren_market.rs b/tee-worker/litentry/core/mock-server/src/daren_market.rs new file mode 100644 index 0000000000..cb1b725522 --- /dev/null +++ b/tee-worker/litentry/core/mock-server/src/daren_market.rs @@ -0,0 +1,48 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . +#![allow(opaque_hidden_inferred_bound)] + +use std::collections::HashMap; + +use lc_data_providers::daren_market::UserVerificationResponse; + +use warp::{http::Response, Filter}; + +pub(crate) fn query() -> impl Filter + Clone { + warp::get() + .and(warp::path!("daren_market" / "api" / "talent-asset")) + .and(warp::query::>()) + .map(move |p: HashMap| { + let default = String::default(); + let address = p.get("address").unwrap_or(&default); + + if address == "0x49ad262c49c7aa708cc2df262ed53b64a17dd5ee" { + let body = UserVerificationResponse { + success: true, + created: true, + message: "Talent Asset Found!".to_string(), + }; + Response::builder().body(serde_json::to_string(&body).unwrap()) + } else { + let body = UserVerificationResponse { + success: false, + created: false, + message: "".to_string(), + }; + Response::builder().body(serde_json::to_string(&body).unwrap()) + } + }) +} diff --git a/tee-worker/litentry/core/mock-server/src/lib.rs b/tee-worker/litentry/core/mock-server/src/lib.rs index 06d849d420..7337fbe9cb 100644 --- a/tee-worker/litentry/core/mock-server/src/lib.rs +++ b/tee-worker/litentry/core/mock-server/src/lib.rs @@ -26,6 +26,7 @@ use warp::Filter; pub mod achainable; pub mod blockchain_info; +pub mod daren_market; pub mod discord_litentry; pub mod discord_official; pub mod geniidata; @@ -76,6 +77,7 @@ pub fn run(port: u16) -> Result { .or(nodereal_jsonrpc::query()) .or(karat_dao::query()) .or(magic_craft::query()) + .or(daren_market::query()) .or(moralis::query_nft()) .or(moralis::query_erc20()) .or(moralis::query_solana()) diff --git a/tee-worker/litentry/core/mock-server/src/nodereal_jsonrpc.rs b/tee-worker/litentry/core/mock-server/src/nodereal_jsonrpc.rs index 5ced7c2400..02be0a405c 100644 --- a/tee-worker/litentry/core/mock-server/src/nodereal_jsonrpc.rs +++ b/tee-worker/litentry/core/mock-server/src/nodereal_jsonrpc.rs @@ -118,7 +118,10 @@ pub(crate) fn query() -> impl Filter "0x1158e460913d00000", // 5000 * 10^18 "0x75438d34c9125839c8b08d21b7f3167281659e3c" => "0x10f0cf064dd59200000", - // 800 + // 120_000 * 10^18 + "0x75438d34c9125839c8b08d21b7f3167281659e4c" => "0x1969368974c05b000000", + // 1_500 * 10 ^ 18 + "0x75438d34c9125839c8b08d21b7f3167281659e5c" => "0x5150ae84a8cdf00000", _ => "0x320", }; let body = RpcResponse { diff --git a/tee-worker/litentry/core/parachain-extrinsic-task/receiver/src/lib.rs b/tee-worker/litentry/core/parachain-extrinsic-task/receiver/src/lib.rs index 083d230d20..dd2deb9c4c 100644 --- a/tee-worker/litentry/core/parachain-extrinsic-task/receiver/src/lib.rs +++ b/tee-worker/litentry/core/parachain-extrinsic-task/receiver/src/lib.rs @@ -11,10 +11,16 @@ use itp_ocall_api::EnclaveOnChainOCallApi; use itp_types::parentchain::ParentchainId; use lc_parachain_extrinsic_task_sender::init_parachain_extrinsic_sender_storage; use log::*; -use std::{format, string::String, sync::Arc, time, vec}; +use std::{ + format, + string::String, + sync::{mpsc::RecvTimeoutError, Arc}, + time, vec, +}; const MAX_BATCH_SIZE: usize = 500; const BATCH_EXTRINSIC_INTERVAL: time::Duration = time::Duration::from_secs(6); +const TASK_RECV_INTERVAL: time::Duration = time::Duration::from_secs(1); pub fn run_parachain_extrinsic_task_receiver( api: Arc, @@ -32,13 +38,18 @@ where loop { let start_time = time::Instant::now(); while start_time.elapsed() < BATCH_EXTRINSIC_INTERVAL { - if let Ok(call) = task_receiver.recv() { - calls.push(call); - } - if calls.len() == MAX_BATCH_SIZE { - break + match task_receiver.recv_timeout(TASK_RECV_INTERVAL) { + Ok(call) => { + calls.push(call); + if calls.len() == MAX_BATCH_SIZE { + break + } + }, + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, } } + if !calls.is_empty() { let extrinsic = match extrinsic_factory.create_batch_extrinsic(calls.drain(..).collect(), None) { diff --git a/tee-worker/litentry/core/scheduled-enclave/Cargo.toml b/tee-worker/litentry/core/scheduled-enclave/Cargo.toml deleted file mode 100644 index 8e6f1904e7..0000000000 --- a/tee-worker/litentry/core/scheduled-enclave/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "lc-scheduled-enclave" -version = "0.8.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -codec = { version = "3.0.0", default-features = false, features = ["derive"], package = "parity-scale-codec" } -lazy_static = { version = "1.1.0", features = ["spin_no_std"] } -log = { version = "0.4", default-features = false } -sp-std = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.42" } -thiserror = { version = "1.0.26", optional = true } - -# sgx-deps -sgx_tstd = { branch = "master", git = "https://github.com/apache/teaclave-sgx-sdk.git", features = ["untrusted_fs"], optional = true } -thiserror-sgx = { package = "thiserror", git = "https://github.com/mesalock-linux/thiserror-sgx", tag = "sgx_1.1.3", optional = true } - -# local dependencies -itp-settings = { path = "../../../core-primitives/settings" } -itp-sgx-io = { path = "../../../core-primitives/sgx/io", default-features = false } -itp-types = { path = "../../../core-primitives/types", default-features = false } - -[features] -default = ["std"] -sgx = [ - "sgx_tstd", - "thiserror-sgx", - "itp-sgx-io/sgx", -] -std = [ - "thiserror", - "itp-sgx-io/std", - "itp-types/std", - "sp-std/std", - "codec/std", -] diff --git a/tee-worker/litentry/core/scheduled-enclave/src/error.rs b/tee-worker/litentry/core/scheduled-enclave/src/error.rs deleted file mode 100644 index 70228b33a0..0000000000 --- a/tee-worker/litentry/core/scheduled-enclave/src/error.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2020-2024 Trust Computing GmbH. -// This file is part of Litentry. -// -// Litentry is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Litentry is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Litentry. If not, see . - -use std::boxed::Box; -#[cfg(feature = "sgx")] -use thiserror_sgx as thiserror; - -pub type Result = core::result::Result; - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("poison lock")] - PoisonLock, - #[error("empty ScheduledEnclave registry")] - EmptyRegistry, - #[error("no previous MRENCLAVE")] - NoPreviousMRENCLAVE, - #[error(transparent)] - Other(#[from] Box), -} - -impl From for Error { - fn from(e: std::io::Error) -> Self { - Self::Other(e.into()) - } -} - -impl From for Error { - #[cfg(feature = "std")] - fn from(e: codec::Error) -> Self { - Self::Other(e.into()) - } - - #[cfg(feature = "sgx")] - fn from(e: codec::Error) -> Self { - Self::Other(std::format!("{:?}", e).into()) - } -} diff --git a/tee-worker/litentry/core/scheduled-enclave/src/io.rs b/tee-worker/litentry/core/scheduled-enclave/src/io.rs deleted file mode 100644 index d97ec25b88..0000000000 --- a/tee-worker/litentry/core/scheduled-enclave/src/io.rs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2020-2024 Trust Computing GmbH. -// This file is part of Litentry. -// -// Litentry is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Litentry is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Litentry. If not, see . - -#[cfg(all(feature = "std", feature = "sgx"))] -compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the same time"); - -use crate::{ - error::{Error, Result}, - MrEnclave, ScheduledEnclave, ScheduledEnclaveUpdater, SidechainBlockNumber, - GLOBAL_SCHEDULED_ENCLAVE, -}; - -#[cfg(feature = "sgx")] -pub mod sgx { - use crate::{ - error::{Error, Result}, - ScheduledEnclaveMap, - }; - pub use codec::{Decode, Encode}; - pub use itp_settings::files::SCHEDULED_ENCLAVE_FILE; - pub use itp_sgx_io::{seal, unseal, SealedIO}; - pub use log::*; - pub use std::{boxed::Box, fs, path::PathBuf, sgxfs::SgxFile, sync::Arc}; - - #[derive(Clone, Debug)] - pub struct ScheduledEnclaveSeal { - base_path: PathBuf, - } - - impl ScheduledEnclaveSeal { - pub fn new(base_path: PathBuf) -> Self { - Self { base_path } - } - - pub fn path(&self) -> PathBuf { - self.base_path.join(SCHEDULED_ENCLAVE_FILE) - } - } - - impl SealedIO for ScheduledEnclaveSeal { - type Error = Error; - type Unsealed = ScheduledEnclaveMap; - - fn unseal(&self) -> Result { - Ok(unseal(self.path()).map(|b| Decode::decode(&mut b.as_slice()))??) - } - - fn seal(&self, unsealed: &Self::Unsealed) -> Result<()> { - info!("Seal scheduled enclave to file: {:?}", unsealed); - Ok(unsealed.using_encoded(|bytes| seal(bytes, self.path()))?) - } - } -} - -#[cfg(feature = "sgx")] -use sgx::*; - -// TODO: unit-test -impl ScheduledEnclaveUpdater for ScheduledEnclave { - #[cfg(feature = "std")] - fn init(&self, _mrenclave: MrEnclave) -> Result<()> { - Ok(()) - } - - #[cfg(feature = "std")] - fn update(&self, _sbn: SidechainBlockNumber, _mrenclave: MrEnclave) -> Result<()> { - Ok(()) - } - - #[cfg(feature = "std")] - fn remove(&self, _sbn: SidechainBlockNumber) -> Result<()> { - Ok(()) - } - - // if `SCHEDULED_ENCLAVE_FILE` exists, unseal and init from it - // otherwise create a new instance and seal to static file - #[cfg(feature = "sgx")] - fn init(&self, mrenclave: MrEnclave) -> Result<()> { - let _ = self.set_current_mrenclave(mrenclave)?; - let _ = self.set_block_production_paused(false)?; - let enclave_seal = ScheduledEnclaveSeal::new(self.seal_path.clone()); - if SgxFile::open(SCHEDULED_ENCLAVE_FILE).is_err() { - info!( - "[Enclave] ScheduledEnclave file not found, creating new! {}", - SCHEDULED_ENCLAVE_FILE - ); - let mut registry = - GLOBAL_SCHEDULED_ENCLAVE.registry.write().map_err(|_| Error::PoisonLock)?; - registry.clear(); - registry.insert(0, mrenclave); - enclave_seal.seal(&*registry) - } else { - let m = enclave_seal.unseal()?; - info!("[Enclave] ScheduledEnclave unsealed from file: {:?}", m); - let mut registry = - GLOBAL_SCHEDULED_ENCLAVE.registry.write().map_err(|_| Error::PoisonLock)?; - *registry = m; - Ok(()) - } - } - - #[cfg(feature = "sgx")] - fn update(&self, sbn: SidechainBlockNumber, mrenclave: MrEnclave) -> Result<()> { - let mut registry = - GLOBAL_SCHEDULED_ENCLAVE.registry.write().map_err(|_| Error::PoisonLock)?; - registry.insert(sbn, mrenclave); - ScheduledEnclaveSeal::new(self.seal_path.clone()).seal(&*registry) - } - - #[cfg(feature = "sgx")] - fn remove(&self, sbn: SidechainBlockNumber) -> Result<()> { - let mut registry = - GLOBAL_SCHEDULED_ENCLAVE.registry.write().map_err(|_| Error::PoisonLock)?; - let old_value = registry.remove(&sbn); - if old_value.is_some() { - return ScheduledEnclaveSeal::new(self.seal_path.clone()).seal(&*registry) - } - Ok(()) - } - - fn get_current_mrenclave(&self) -> Result { - self.current_mrenclave.read().map_err(|_| Error::PoisonLock).map(|l| *l) - } - - fn set_current_mrenclave(&self, mrenclave: MrEnclave) -> Result<()> { - let mut m = self.current_mrenclave.write().map_err(|_| Error::PoisonLock)?; - *m = mrenclave; - Ok(()) - } - - fn get_expected_mrenclave(&self, sbn: SidechainBlockNumber) -> Result { - let registry = GLOBAL_SCHEDULED_ENCLAVE.registry.read().map_err(|_| Error::PoisonLock)?; - let r = registry - .iter() - .filter(|(k, _)| **k <= sbn) - .max_by_key(|(k, _)| **k) - .ok_or(Error::EmptyRegistry)?; - Ok(*r.1) - } - - fn get_previous_mrenclave(&self, sbn: SidechainBlockNumber) -> Result { - // TODO: optimise it - let registry = GLOBAL_SCHEDULED_ENCLAVE.registry.read().map_err(|_| Error::PoisonLock)?; - let r = registry - .iter() - .filter(|(k, _)| **k <= sbn) - .max_by_key(|(k, _)| **k) - .ok_or(Error::NoPreviousMRENCLAVE)?; - let v = registry - .iter() - .filter(|(k, _)| **k < *r.0) - .max_by_key(|(k, _)| **k) - .ok_or(Error::NoPreviousMRENCLAVE)?; - Ok(*v.1) - } - - fn is_block_production_paused(&self) -> Result { - self.block_production_paused.read().map_err(|_| Error::PoisonLock).map(|l| *l) - } - - fn set_block_production_paused(&self, should_pause: bool) -> Result<()> { - let mut p = self.block_production_paused.write().map_err(|_| Error::PoisonLock)?; - *p = should_pause; - Ok(()) - } -} diff --git a/tee-worker/litentry/core/scheduled-enclave/src/lib.rs b/tee-worker/litentry/core/scheduled-enclave/src/lib.rs deleted file mode 100644 index 609d688c2f..0000000000 --- a/tee-worker/litentry/core/scheduled-enclave/src/lib.rs +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2020-2024 Trust Computing GmbH. -// This file is part of Litentry. -// -// Litentry is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Litentry is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Litentry. If not, see . - -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(all(feature = "std", feature = "sgx"))] -compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the same time"); - -#[cfg(feature = "sgx")] -extern crate sgx_tstd as std; - -// TODO: maybe use parachain primitives for single source of truth -use itp_types::{MrEnclave, SidechainBlockNumber}; -use sp_std::collections::btree_map::BTreeMap; -use std::path::PathBuf; - -pub mod error; -use error::Result; -pub mod io; -#[cfg(feature = "sgx")] -pub use io::sgx::ScheduledEnclaveSeal; - -#[cfg(feature = "std")] -use std::sync::RwLock; -#[cfg(feature = "sgx")] -use std::sync::SgxRwLock as RwLock; - -use lazy_static::lazy_static; -use std::sync::Arc; - -pub mod mock; - -lazy_static! { - /// Global instance of a ScheduledEnclave - pub static ref GLOBAL_SCHEDULED_ENCLAVE: Arc = Default::default(); -} - -pub type ScheduledEnclaveMap = BTreeMap; - -#[derive(Default)] -pub struct ScheduledEnclave { - pub block_production_paused: RwLock, - pub current_mrenclave: RwLock, - pub registry: RwLock, - pub seal_path: PathBuf, -} - -pub trait ScheduledEnclaveUpdater { - fn init(&self, mrenclave: MrEnclave) -> Result<()>; - - fn update(&self, sbn: SidechainBlockNumber, mrenclave: MrEnclave) -> Result<()>; - - fn remove(&self, sbn: SidechainBlockNumber) -> Result<()>; - - fn get_current_mrenclave(&self) -> Result; - - fn set_current_mrenclave(&self, mrenclave: MrEnclave) -> Result<()>; - - // given a SidechainBlockNumber, return the expected MRENCLAVE - // For example, the registry is: - // 0 -> 0xAA - // 19 -> 0xBB - // 21 -> 0xCC - // - // get_expected_mrenclave(0) -> 0xAA - // get_expected_mrenclave(18) -> 0xAA - // get_expected_mrenclave(19) -> 0xBB - // get_expected_mrenclave(20) -> 0xBB - // get_expected_mrenclave(21) -> 0xCC - // get_expected_mrenclave(30) -> 0xCC - fn get_expected_mrenclave(&self, sbn: SidechainBlockNumber) -> Result; - - // given a SidechainBlockNumber, return the previous MRENCLAVE - // we can't simply use `get_previous_mrenclave(sbn - 1)` due to possible gap - // For example, the registry is: - // 0 -> 0xAA - // 19 -> 0xBB - // 21 -> 0xCC - // - // get_previous_mrenclave(0) -> NoPreviousMRENCLAVE error - // get_previous_mrenclave(1) -> NoPreviousMRENCLAVE error - // get_previous_mrenclave(19) -> 0xAA - // get_previous_mrenclave(20) -> 0xAA - // get_previous_mrenclave(21) -> 0xBB - // get_previous_mrenclave(30) -> 0xBB - fn get_previous_mrenclave(&self, sbn: SidechainBlockNumber) -> Result; - - fn is_block_production_paused(&self) -> Result; - - fn set_block_production_paused(&self, should_pause: bool) -> Result<()>; - - fn is_mrenclave_matching(&self, sbn: SidechainBlockNumber) -> bool { - let current = self.get_current_mrenclave(); - let expected = self.get_expected_mrenclave(sbn); - - if current.is_err() || expected.is_err() { - return false - } - - current.unwrap() == expected.unwrap() - } -} - -#[derive(Default)] -pub struct ScheduledEnclaveMock; - -// todo! -impl ScheduledEnclaveUpdater for ScheduledEnclaveMock { - fn init(&self, _mrenclave: MrEnclave) -> Result<()> { - Ok(()) - } - - fn update(&self, _sbn: SidechainBlockNumber, _mrenclave: MrEnclave) -> Result<()> { - Ok(()) - } - - fn remove(&self, _sbn: SidechainBlockNumber) -> Result<()> { - Ok(()) - } - - fn get_current_mrenclave(&self) -> Result { - Ok(MrEnclave::default()) - } - - fn set_current_mrenclave(&self, _mrenclave: MrEnclave) -> Result<()> { - Ok(()) - } - - fn get_expected_mrenclave(&self, _sbn: SidechainBlockNumber) -> Result { - Ok(MrEnclave::default()) - } - - fn get_previous_mrenclave(&self, _sbn: SidechainBlockNumber) -> Result { - Ok(MrEnclave::default()) - } - - fn is_block_production_paused(&self) -> Result { - Ok(false) - } - - fn set_block_production_paused(&self, _should_pause: bool) -> Result<()> { - Ok(()) - } -} diff --git a/tee-worker/litentry/core/scheduled-enclave/src/mock.rs b/tee-worker/litentry/core/scheduled-enclave/src/mock.rs deleted file mode 100644 index d550892553..0000000000 --- a/tee-worker/litentry/core/scheduled-enclave/src/mock.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::{ - error::{Error, Result}, - ScheduledEnclaveMap, -}; -pub use itp_sgx_io::SealedIO; -pub use std::path::PathBuf; - -#[derive(Clone, Debug, Default)] -pub struct ScheduledEnclaveSealMock {} - -impl ScheduledEnclaveSealMock { - pub fn new() -> Self { - Self {} - } -} - -impl SealedIO for ScheduledEnclaveSealMock { - type Error = Error; - type Unsealed = ScheduledEnclaveMap; - - fn unseal(&self) -> Result { - Ok(ScheduledEnclaveMap::default()) - } - - fn seal(&self, _unsealed: &Self::Unsealed) -> Result<()> { - Ok(()) - } -} diff --git a/tee-worker/litentry/core/service/src/platform_user/daren_market_user.rs b/tee-worker/litentry/core/service/src/platform_user/daren_market_user.rs new file mode 100644 index 0000000000..7591897ddb --- /dev/null +++ b/tee-worker/litentry/core/service/src/platform_user/daren_market_user.rs @@ -0,0 +1,58 @@ +// Copyright 2020-2024 Trust Computing GmbH. +// This file is part of Litentry. +// +// Litentry is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Litentry is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Litentry. If not, see . + +#[cfg(all(feature = "std", feature = "sgx"))] +compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the same time"); + +#[cfg(all(not(feature = "std"), feature = "sgx"))] +extern crate sgx_tstd as std; + +use core::result::Result; +use std::string::ToString; + +use lc_common::abort_strategy::{loop_with_abort_strategy, AbortStrategy, LoopControls}; +use lc_data_providers::{ + daren_market::{DarenMarketApi, DarenMarketClient}, + DataProviderConfig, +}; + +use crate::*; + +pub fn is_user( + addresses: Vec, + data_provider_config: &DataProviderConfig, +) -> Result { + let mut result = false; + let mut client = DarenMarketClient::new(data_provider_config); + + loop_with_abort_strategy( + addresses, + |address| match client.user_verification(address.to_string(), true) { + Ok(response) => + if response.created { + result = true; + Ok(LoopControls::Break) + } else { + Ok(LoopControls::Continue) + }, + Err(err) => Err(err.into_error_detail()), + }, + AbortStrategy::ContinueUntilEnd:: bool>, + ) + .map_err(|errors| errors[0].clone())?; + + Ok(result) +} diff --git a/tee-worker/litentry/core/service/src/platform_user/mod.rs b/tee-worker/litentry/core/service/src/platform_user/mod.rs index eb34778bc8..e02f9e5cec 100644 --- a/tee-worker/litentry/core/service/src/platform_user/mod.rs +++ b/tee-worker/litentry/core/service/src/platform_user/mod.rs @@ -27,6 +27,7 @@ use litentry_primitives::PlatformUserType; use crate::*; +mod daren_market_user; mod karat_dao_user; mod magic_craft_staking_user; @@ -36,8 +37,10 @@ pub fn is_user( data_provider_config: &DataProviderConfig, ) -> Result { match platform_user_type { - PlatformUserType::KaratDaoUser => karat_dao_user::is_user(addresses, data_provider_config), - PlatformUserType::MagicCraftStakingUser => + PlatformUserType::KaratDao => karat_dao_user::is_user(addresses, data_provider_config), + PlatformUserType::MagicCraftStaking => magic_craft_staking_user::is_user(addresses, data_provider_config), + PlatformUserType::DarenMarket => + daren_market_user::is_user(addresses, data_provider_config), } } diff --git a/tee-worker/litentry/core/service/src/web3_nft/nft_holder/common.rs b/tee-worker/litentry/core/service/src/web3_nft/nft_holder/common.rs index 055626652a..b2e730cfb0 100644 --- a/tee-worker/litentry/core/service/src/web3_nft/nft_holder/common.rs +++ b/tee-worker/litentry/core/service/src/web3_nft/nft_holder/common.rs @@ -75,6 +75,23 @@ pub fn has_nft_721( None => Ok(LoopControls::Continue), } }, + Web3Network::Polygon => { + match check_nft_via_moralis( + network, + address.1.clone(), + token_address.into(), + data_provider_config, + ) { + Ok(r) => { + if r { + result = true; + return Ok(LoopControls::Break) + } + Ok(LoopControls::Continue) + }, + Err(err) => Err(err), + } + }, _ => Ok(LoopControls::Continue), } }, @@ -85,6 +102,50 @@ pub fn has_nft_721( Ok(result) } +pub fn check_nft_via_moralis( + network: Web3Network, + address: String, + token_address: String, + data_provider_config: &DataProviderConfig, +) -> Result { + let mut client = MoralisClient::new(data_provider_config); + + match network { + Web3Network::Bsc | Web3Network::Ethereum | Web3Network::Polygon | Web3Network::Arbitrum => { + let mut cursor: Option = None; + 'inner: loop { + let param = GetNftsByWalletParam { + address: address.clone(), + chain: MoralisChainParam::new(&network), + token_addresses: Some(vec![token_address.clone()]), + limit: None, + cursor, + }; + match client.get_nfts_by_wallet(¶m, false) { + Ok(resp) => { + cursor = resp.cursor; + for item in &resp.result { + match item.amount.parse::() { + Ok(balance) => + if balance > 0 { + return Ok(true) + }, + Err(_) => return Err(ErrorDetail::ParseError), + } + } + }, + Err(err) => return Err(err.into_error_detail()), + } + if cursor.is_none() { + break 'inner + } + } + Ok(false) + }, + _ => Ok(false), + } +} + // support ERC1155/BEP1155 nft token pub fn has_nft_1155( addresses: Vec<(Web3Network, String)>, @@ -92,7 +153,6 @@ pub fn has_nft_1155( data_provider_config: &DataProviderConfig, ) -> Result { let mut result = false; - let mut client = MoralisClient::new(data_provider_config); loop_with_abort_strategy( addresses, @@ -105,36 +165,21 @@ pub fn has_nft_1155( | Web3Network::Ethereum | Web3Network::Polygon | Web3Network::Arbitrum => { - let mut cursor: Option = None; - 'inner: loop { - let param = GetNftsByWalletParam { - address: address.1.clone(), - chain: MoralisChainParam::new(&network), - token_addresses: Some(vec![token_address.into()]), - limit: None, - cursor, - }; - match client.get_nfts_by_wallet(¶m, false) { - Ok(resp) => { - cursor = resp.cursor; - for item in &resp.result { - match item.amount.parse::() { - Ok(balance) => - if balance > 0 { - result = true; - return Ok(LoopControls::Break) - }, - Err(_) => return Err(ErrorDetail::ParseError), - } - } - }, - Err(err) => return Err(err.into_error_detail()), - } - if cursor.is_none() { - break 'inner - } + match check_nft_via_moralis( + network, + address.1.clone(), + token_address.into(), + data_provider_config, + ) { + Ok(r) => { + if r { + result = true; + return Ok(LoopControls::Break) + } + Ok(LoopControls::Continue) + }, + Err(err) => Err(err), } - Ok(LoopControls::Continue) }, _ => Ok(LoopControls::Continue), } diff --git a/tee-worker/litentry/core/service/src/web3_nft/nft_holder/mod.rs b/tee-worker/litentry/core/service/src/web3_nft/nft_holder/mod.rs index 8f24d928ef..5bef38afaa 100644 --- a/tee-worker/litentry/core/service/src/web3_nft/nft_holder/mod.rs +++ b/tee-worker/litentry/core/service/src/web3_nft/nft_holder/mod.rs @@ -31,9 +31,9 @@ pub fn has_nft( addresses: Vec<(Web3Network, String)>, data_provider_config: &DataProviderConfig, ) -> Result { - match nft_type { - Web3NftType::WeirdoGhostGang => - common::has_nft_721(addresses, nft_type, data_provider_config), - Web3NftType::Club3Sbt => common::has_nft_1155(addresses, nft_type, data_provider_config), + if nft_type == Web3NftType::Club3Sbt { + common::has_nft_1155(addresses, nft_type, data_provider_config) + } else { + common::has_nft_721(addresses, nft_type, data_provider_config) } } diff --git a/tee-worker/litentry/core/stf-task/receiver/src/handler/assertion.rs b/tee-worker/litentry/core/stf-task/receiver/src/handler/assertion.rs index f3ce9415da..97e2fc8767 100644 --- a/tee-worker/litentry/core/stf-task/receiver/src/handler/assertion.rs +++ b/tee-worker/litentry/core/stf-task/receiver/src/handler/assertion.rs @@ -37,7 +37,13 @@ use litentry_primitives::{ }; use log::*; use sp_core::{Pair, H160}; -use std::{format, string::ToString, sync::Arc, vec::Vec}; +use std::{ + format, + iter::once, + string::{String, ToString}, + sync::Arc, + vec::Vec, +}; pub(crate) struct AssertionHandler< ShieldingKeyRepository, @@ -67,7 +73,7 @@ where AR: AssertionLogicRepository, { type Error = VCMPError; - type Result = Vec; // vc_byte_array + type Result = (Vec, Option>); // (vc_byte_array, optional vc_log_byte_array) fn on_process(&self) -> Result { // create the initial credential @@ -83,7 +89,7 @@ where debug!("Assertion build OK"); // we shouldn't have the maximum text length limit in normal RSA3072 encryption, as the payload // using enclave's shielding key is encrypted in chunks - let vc_payload = result; + let vc_payload = result.0; if let Ok(enclave_signer_account) = self.context.enclave_signer.get_enclave_account() { let c = TrustedCall::request_vc_callback( enclave_signer_account.into(), @@ -143,11 +149,12 @@ pub fn create_credential_str< >( req: &AssertionBuildRequest, context: &Arc>, -) -> Result, VCMPError> +) -> Result<(Vec, Option>), VCMPError> where ShieldingKeyRepository: AccessKey, ::KeyType: ShieldingCryptoEncrypt + 'static, { + let mut vc_logs: Option> = None; let mut credential = match req.assertion.clone() { Assertion::A1 => { #[cfg(test)] @@ -277,13 +284,15 @@ where Assertion::NftHolder(nft_type) => lc_assertion_build_v2::nft_holder::build(req, nft_type, &context.data_provider_config), - Assertion::Dynamic(smart_contract_id, smart_contract_params) => - lc_assertion_build::dynamic::build( + Assertion::Dynamic(params) => { + let result = lc_assertion_build::dynamic::build( req, - smart_contract_id, - smart_contract_params, + params, context.assertion_repository.clone(), - ), + )?; + vc_logs = Some(result.1); + Ok(result.0) + }, }?; // post-process the credential @@ -335,5 +344,11 @@ where .to_json() .map_err(|_| VCMPError::RequestVCFailed(req.assertion.clone(), ErrorDetail::ParseError))?; debug!("Credential: {}, length: {}", credential_str, credential_str.len()); - Ok(credential_str.as_bytes().to_vec()) + + Ok(( + credential_str.as_bytes().to_vec(), + vc_logs.map(|v| { + v.iter().flat_map(|s| s.as_bytes().iter().cloned().chain(once(b'\n'))).collect() + }), + )) } diff --git a/tee-worker/litentry/core/stf-task/receiver/src/lib.rs b/tee-worker/litentry/core/stf-task/receiver/src/lib.rs index d3f66e04db..8a7b431c43 100644 --- a/tee-worker/litentry/core/stf-task/receiver/src/lib.rs +++ b/tee-worker/litentry/core/stf-task/receiver/src/lib.rs @@ -236,7 +236,6 @@ where let context_cloned = context.clone(); thread::spawn(move || loop { if let Ok((shard, hash, call)) = receiver.recv() { - info!("Submitting trusted call to the pool"); if let Err(e) = context_cloned.submit_trusted_call(&shard, Some(hash), &call) { error!("Submit Trusted Call failed: {:?}", e); } diff --git a/tee-worker/litentry/core/vc-task/receiver/src/lib.rs b/tee-worker/litentry/core/vc-task/receiver/src/lib.rs index c427bbc170..d72c915e6f 100644 --- a/tee-worker/litentry/core/vc-task/receiver/src/lib.rs +++ b/tee-worker/litentry/core/vc-task/receiver/src/lib.rs @@ -56,7 +56,7 @@ use lc_evm_dynamic_assertions::AssertionRepositoryItem; use lc_parachain_extrinsic_task_sender::{ParachainExtrinsicSender, SendParachainExtrinsic}; use lc_stf_task_receiver::{handler::assertion::create_credential_str, StfTaskContext}; use lc_stf_task_sender::AssertionBuildRequest; -use lc_vc_task_sender::init_vc_task_sender_storage; +use lc_vc_task_sender::init_vc_task_sender; use litentry_macros::if_development_or; use litentry_primitives::{Assertion, DecryptableRequest, Identity, ParentchainBlockNumber}; use log::*; @@ -92,7 +92,7 @@ pub fn run_vc_handler_runner( N::MetadataType: NodeMetadataTrait, AR: AssertionLogicRepository + Send + Sync + 'static, { - let vc_task_receiver = init_vc_task_sender_storage(); + let vc_task_receiver = init_vc_task_sender(); let n_workers = 960; let pool = ThreadPoolBuilder::new().pool_size(n_workers).create().unwrap(); @@ -103,7 +103,6 @@ pub fn run_vc_handler_runner( let context_cloned = context.clone(); thread::spawn(move || loop { if let Ok((shard, call)) = tc_receiver.recv() { - info!("Submitting trusted call to the pool"); if let Err(e) = context_cloned.submit_trusted_call(&shard, None, &call) { error!("Submit Trusted Call failed: {:?}", e); } @@ -434,6 +433,11 @@ where // The `call` should always be `TrustedCall:request_vc`. Once decided to remove 'request_vc', this part can be refactored regarding the parameters. if let TrustedCall::request_vc(signer, who, assertion, maybe_key, req_ext_hash) = call { + info!( + "Processing vc request for {}, assertion: {:?}", + who.to_did().unwrap_or_default(), + assertion + ); let (mut id_graph, is_already_linked, parachain_block_number, sidechain_block_number) = context .state_handler @@ -481,7 +485,7 @@ where let mut should_create_id_graph = false; if id_graph.is_empty() { - info!("IDGraph is empty, will pre-create one"); + debug!("IDGraph is empty, will pre-create one"); // To create IDGraph upon first vc request (see P-410), there're two options: // // 1. synchronous creation: @@ -555,13 +559,13 @@ where req_ext_hash, }; - let credential_str = create_credential_str(&req, &context) + let (vc_payload, vc_logs) = create_credential_str(&req, &context) .map_err(|e| RequestVcErrorDetail::AssertionBuildFailed(Box::new(e)))?; let call_index = node_metadata_repo .get_from_metadata(|m| m.vc_issued_call_indexes()) .map_err(|e| RequestVcErrorDetail::MetadataRetrievalFailed(e.to_string()))? - .map_err(|e| RequestVcErrorDetail::InvalidMetadata(format!("{:?}", e))); + .map_err(|e| RequestVcErrorDetail::InvalidMetadata(format!("{:?}", e)))?; let key = maybe_key.ok_or(RequestVcErrorDetail::MissingAesKey)?; let call = OpaqueCall::from_tuple(&( @@ -575,7 +579,8 @@ where let mutated_id_graph = if should_create_id_graph { id_graph } else { Default::default() }; let res = RequestVCResult { - vc_payload: aes_encrypt_default(&key, &credential_str), + vc_payload: aes_encrypt_default(&key, &vc_payload), + vc_logs: vc_logs.map(|v| aes_encrypt_default(&key, &v)), pre_mutated_id_graph: aes_encrypt_default(&key, &mutated_id_graph.encode()), pre_id_graph_hash: id_graph_hash, }; @@ -585,7 +590,7 @@ where .enclave_signer .get_enclave_account() .map_err(|_| RequestVcErrorDetail::EnclaveSignerRetrievalFailed)?; - let c = TrustedCall::maybe_create_id_graph(enclave_signer.into(), who); + let c = TrustedCall::maybe_create_id_graph(enclave_signer.into(), who.clone()); tc_sender .send((shard, c)) .map_err(|e| RequestVcErrorDetail::TrustedCallSendingFailed(e.to_string()))?; @@ -595,11 +600,12 @@ where if let Err(e) = context .ocall_api - .update_metric(EnclaveMetric::VCBuildTime(assertion, start_time.elapsed())) + .update_metric(EnclaveMetric::VCBuildTime(assertion.clone(), start_time.elapsed())) { warn!("Failed to update metric for vc build time: {:?}", e); } + info!("Vc issued for {}, assertion: {:?}", who.to_did().unwrap_or_default(), assertion); Ok(res.encode()) } else { // Would never come here. diff --git a/tee-worker/litentry/core/vc-task/sender/src/lib.rs b/tee-worker/litentry/core/vc-task/sender/src/lib.rs index f6ff6ae6b1..8ade6f3a87 100644 --- a/tee-worker/litentry/core/vc-task/sender/src/lib.rs +++ b/tee-worker/litentry/core/vc-task/sender/src/lib.rs @@ -25,7 +25,7 @@ use std::sync::Mutex; use std::sync::SgxMutex as Mutex; use std::{ format, - string::String, + string::{String, ToString}, sync::{ mpsc::{channel, Receiver, Sender as MpscSender}, Arc, @@ -62,7 +62,7 @@ impl VcRequestSender { pub fn send(&self, request: VCRequest) -> Result<(), String> { debug!("send vc request: {:?}", request); - // Acquire lock on extrinsic sender + // Acquire lock on vc task sender let mutex_guard = GLOBAL_VC_TASK_SENDER.lock().map_err(|_| "Could not access Mutex")?; let vc_task_sender = mutex_guard.clone().ok_or("Daemon sender was not initialized")?; // Release mutex lock, so we don't block the lock longer than necessary. @@ -75,30 +75,47 @@ impl VcRequestSender { } } -/// Initialization of the extrinsic sender. Needs to be called before any sender access. -pub fn init_vc_task_sender_storage() -> Receiver { +/// Initialization of the vc task sender. Needs to be called before any sender access. +pub fn init_vc_task_sender() -> Receiver { let (sender, receiver) = channel(); // It makes no sense to handle the unwrap, as this statement fails only if the lock has been poisoned // I believe at that point it is an unrecoverable error - let mut vc_task_storage = GLOBAL_VC_TASK_SENDER.lock().unwrap(); - *vc_task_storage = Some(VcTaskSender::new(sender)); + let mut vc_task_sender = GLOBAL_VC_TASK_SENDER.lock().unwrap(); + *vc_task_sender = Some(VcTaskSender::new(sender, false)); receiver } +pub fn pause_vc_task_sender() -> Result<(), String> { + info!("Pause vc task sender"); + let mut mutex_guard = GLOBAL_VC_TASK_SENDER.lock().map_err(|_| "Could not access Mutex")?; + let sender = mutex_guard.as_mut().ok_or("Daemon sender was not initialized")?; + sender.set_paused(true); + Ok(()) +} + /// Wrapping struct around the actual sender. Should not be accessed directly. (unnecessary) #[derive(Clone, Debug)] struct VcTaskSender { sender: VcSender, + paused: bool, } impl VcTaskSender { - pub fn new(sender: VcSender) -> Self { - Self { sender } + pub fn new(sender: VcSender, paused: bool) -> Self { + Self { sender, paused } + } + + pub fn set_paused(&mut self, paused: bool) { + self.paused = paused; } fn send(&self, request: VCRequest) -> Result<(), String> { + if self.paused { + return Err("Failed to send vc task: sender is paused".to_string()) + } + self.sender .send(request) - .map_err(|e| format!("Failed to send message to VC Handler: {:?}", e)) + .map_err(|e| format!("Failed to send vc task: {:?}", e)) } } diff --git a/tee-worker/litentry/primitives/src/bitcoin_address.rs b/tee-worker/litentry/primitives/src/bitcoin_address.rs index 32dcdcafcb..ae3f58f7cf 100644 --- a/tee-worker/litentry/primitives/src/bitcoin_address.rs +++ b/tee-worker/litentry/primitives/src/bitcoin_address.rs @@ -16,7 +16,8 @@ */ use bitcoin::{ - address::Address, key::PublicKey, network::Network, secp256k1::Secp256k1, XOnlyPublicKey, + address::Address, key::PublicKey, network::Network, secp256k1::Secp256k1, Script, + XOnlyPublicKey, }; use core::str::FromStr; use std::string::{String, ToString}; @@ -55,3 +56,9 @@ pub fn p2pkh_address(pubkey_string: &str) -> String { let address = Address::p2pkh(&pubkey, Network::Bitcoin); address.to_string() } + +pub fn p2wsh_address(pubkey_string: &str) -> String { + let script = Script::from_bytes(pubkey_string.as_bytes()); + let address = Address::p2wsh(script, Network::Bitcoin); + address.to_string() +} diff --git a/tee-worker/litentry/primitives/src/lib.rs b/tee-worker/litentry/primitives/src/lib.rs index f49683cc68..da8d5e8e94 100644 --- a/tee-worker/litentry/primitives/src/lib.rs +++ b/tee-worker/litentry/primitives/src/lib.rs @@ -43,7 +43,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use itp_sgx_crypto::ShieldingCryptoDecrypt; use log::error; pub use pallet_teebag::{ - decl_rsa_request, extract_tcb_info_from_raw_dcap_quote, AttestationType, Enclave, + decl_rsa_request, extract_tcb_info_from_raw_dcap_quote, AttestationType, DcapProvider, Enclave, EnclaveFingerprint, MrEnclave, ShardIdentifier, SidechainBlockNumber, WorkerMode, WorkerType, }; pub use parentchain_primitives::{ @@ -56,6 +56,7 @@ pub use parentchain_primitives::{ }, bnb_domain::BnbDigitDomainType, contest::ContestType, + dynamic::{DynamicContractParams, DynamicParams}, evm_amount_holding::EVMTokenType, generic_discord_role::GenericDiscordRoleType, network::{ @@ -72,10 +73,10 @@ pub use parentchain_primitives::{ }, identity::*, AccountId as ParentchainAccountId, Balance as ParentchainBalance, - BlockNumber as ParentchainBlockNumber, DynamicParams, ErrorDetail, ErrorString, - Hash as ParentchainHash, Header as ParentchainHeader, IMPError, Index as ParentchainIndex, - IntoErrorDetail, ParameterString, SchemaContentString, SchemaIdString, - Signature as ParentchainSignature, VCMPError, MINUTES, + BlockNumber as ParentchainBlockNumber, ErrorDetail, ErrorString, Hash as ParentchainHash, + Header as ParentchainHeader, IMPError, Index as ParentchainIndex, IntoErrorDetail, + ParameterString, SchemaContentString, SchemaIdString, Signature as ParentchainSignature, + VCMPError, MINUTES, }; use scale_info::TypeInfo; use sp_core::{ecdsa, ed25519, sr25519, ByteArray}; diff --git a/tee-worker/service/src/cli.yml b/tee-worker/service/src/cli.yml index 72467e7699..2b33dd20a5 100644 --- a/tee-worker/service/src/cli.yml +++ b/tee-worker/service/src/cli.yml @@ -184,16 +184,7 @@ subcommands: index: 1 help: shard identifier base58 encoded - migrate-shard: - about: Migrate shard - args: - - old-shard: - long: old-shard - help: shard identifier hex encoded - takes_value: true - - new-shard: - long: new-shard - help: shard identifier hex encoded - takes_value: true + about: Migrate state from old shards to the new(current) shard, which is identical to mrenclave - test: about: Run tests involving the enclave takes_value: true diff --git a/tee-worker/service/src/config.rs b/tee-worker/service/src/config.rs index fc89b3ebbb..6659eb7576 100644 --- a/tee-worker/service/src/config.rs +++ b/tee-worker/service/src/config.rs @@ -17,7 +17,7 @@ use clap::ArgMatches; use itc_rest_client::rest_client::Url; -use itp_types::parentchain::ParentchainId; +use itp_types::{parentchain::ParentchainId, ShardIdentifier}; use parse_duration::parse; use serde::{Deserialize, Serialize}; use std::{ @@ -362,6 +362,7 @@ impl From<&ArgMatches<'_>> for RunConfig { i ), }); + Self { skip_ra, dev, shard, marblerun_base_url, shielding_target } } } diff --git a/tee-worker/service/src/enclave/tls_ra.rs b/tee-worker/service/src/enclave/tls_ra.rs index cc07e3f4e9..83e4f4d0a1 100644 --- a/tee-worker/service/src/enclave/tls_ra.rs +++ b/tee-worker/service/src/enclave/tls_ra.rs @@ -81,7 +81,12 @@ pub fn enclave_request_state_provisioning Some(quote_size), Err(e) => return Err(e), @@ -90,7 +95,7 @@ pub fn enclave_request_state_provisioning Some(quote_size), Err(e) => return Err(e), diff --git a/tee-worker/service/src/main_impl.rs b/tee-worker/service/src/main_impl.rs index 1099441966..e6b647fc2c 100644 --- a/tee-worker/service/src/main_impl.rs +++ b/tee-worker/service/src/main_impl.rs @@ -252,7 +252,10 @@ pub(crate) fn main() { enclave.dump_dcap_ra_cert_to_disk().unwrap(); } } else if matches.is_present("mrenclave") { - println!("{}", enclave.get_fingerprint().unwrap().encode().to_base58()); + let mrenclave = enclave.get_fingerprint().unwrap(); + let hex_value = hex::encode(mrenclave); + println!("MRENCLAVE hex: {}", hex_value); + println!("MRENCLAVE base58: {}", mrenclave.encode().to_base58()); } else if let Some(sub_matches) = matches.subcommand_matches("init-shard") { setup::init_shard( enclave.as_ref(), @@ -286,32 +289,10 @@ pub(crate) fn main() { tests::run_enclave_tests(sub_matches); } } else if let Some(sub_matches) = matches.subcommand_matches("migrate-shard") { - // This subcommand `migrate-shard` is only used for manual testing. Maybe deleted later. - let old_shard = sub_matches - .value_of("old-shard") - .map(|value| { - let mut shard = [0u8; 32]; - hex::decode_to_slice(value, &mut shard) - .expect("shard must be hex encoded without 0x"); - ShardIdentifier::from_slice(&shard) - }) - .unwrap(); - - let new_shard: ShardIdentifier = sub_matches - .value_of("new-shard") - .map(|value| { - let mut shard = [0u8; 32]; - hex::decode_to_slice(value, &mut shard) - .expect("shard must be hex encoded without 0x"); - ShardIdentifier::from_slice(&shard) - }) - .unwrap(); - - if old_shard == new_shard { - info!("old_shard should not be the same as new_shard"); - } else { - setup::migrate_shard(enclave.as_ref(), &old_shard, &new_shard); - } + let new_shard = extract_shard(None, enclave.as_ref()); + setup::migrate_shard(enclave.as_ref(), &new_shard); + let new_shard_name = new_shard.encode().to_base58(); + setup::remove_old_shards(config.data_dir(), &new_shard_name); } else { info!("For options: use --help"); } diff --git a/tee-worker/service/src/ocall_bridge/bridge_api.rs b/tee-worker/service/src/ocall_bridge/bridge_api.rs index 71899760c1..88bfd7fb3f 100644 --- a/tee-worker/service/src/ocall_bridge/bridge_api.rs +++ b/tee-worker/service/src/ocall_bridge/bridge_api.rs @@ -43,7 +43,7 @@ pub struct Bridge; impl Bridge { pub fn get_ra_api() -> Arc { - debug!("Requesting RemoteAttestation OCall API instance"); + trace!("Requesting RemoteAttestation OCall API instance"); COMPONENT_FACTORY .read() @@ -61,7 +61,7 @@ impl Bridge { } pub fn get_oc_api() -> Arc { - debug!("Requesting WorkerOnChain OCall API instance"); + trace!("Requesting WorkerOnChain OCall API instance"); COMPONENT_FACTORY .read() @@ -71,7 +71,7 @@ impl Bridge { } pub fn get_ipfs_api() -> Arc { - debug!("Requesting IPFS OCall API instance"); + trace!("Requesting IPFS OCall API instance"); COMPONENT_FACTORY .read() @@ -89,7 +89,7 @@ impl Bridge { } pub fn initialize(component_factory: Arc) { - debug!("Initializing OCall bridge with component factory"); + trace!("Initializing OCall bridge with component factory"); *COMPONENT_FACTORY.write() = Some(component_factory); } diff --git a/tee-worker/service/src/ocall_bridge/ffi/get_peers.rs b/tee-worker/service/src/ocall_bridge/ffi/get_peers.rs index 2cc380d6e4..8f2fb6badc 100644 --- a/tee-worker/service/src/ocall_bridge/ffi/get_peers.rs +++ b/tee-worker/service/src/ocall_bridge/ffi/get_peers.rs @@ -17,7 +17,7 @@ fn get_trusted_peers_urls( peers_size: u32, sidechain_api: Arc, ) -> sgx_status_t { - debug!(" Entering ocall_get_trusted_peers_urls"); + trace!(" Entering ocall_get_trusted_peers_urls"); let peers_encoded = match sidechain_api.get_trusted_peers_urls() { Ok(r) => r, diff --git a/tee-worker/service/src/ocall_bridge/worker_on_chain_ocall.rs b/tee-worker/service/src/ocall_bridge/worker_on_chain_ocall.rs index 5bf574a57b..3e1b181b78 100644 --- a/tee-worker/service/src/ocall_bridge/worker_on_chain_ocall.rs +++ b/tee-worker/service/src/ocall_bridge/worker_on_chain_ocall.rs @@ -83,7 +83,7 @@ where request: Vec, parentchain_id: Vec, ) -> OCallBridgeResult> { - debug!(" Entering ocall_worker_request"); + trace!(" Entering ocall_worker_request"); let requests: Vec = Decode::decode(&mut request.as_slice())?; if requests.is_empty() { diff --git a/tee-worker/service/src/parentchain_handler.rs b/tee-worker/service/src/parentchain_handler.rs index 41cfd13515..d4f59fd3bb 100644 --- a/tee-worker/service/src/parentchain_handler.rs +++ b/tee-worker/service/src/parentchain_handler.rs @@ -220,7 +220,7 @@ where id, curr_block_number, until_synced_header.number, immediate_import, format_duration(remaining_time_estimate) ); } - debug!( + trace!( "[{:?}] Found {} block(s) to sync in this chunk. immediate import={} ", id, block_chunk_to_sync.len(), @@ -252,7 +252,7 @@ where self.parentchain_api.get_events_for_block(Some(block.block.header.hash())) }) .collect::, _>>()?; - debug!("[{:?}] Found {} event vector(s) to sync in this chunk", id, evs.len()); + trace!("[{:?}] Found {} event vector(s) to sync in this chunk", id, evs.len()); evs }; @@ -290,7 +290,7 @@ where .expect("Can decode previously encoded header; qed"); start_block = until_synced_header.number + 1; - println!( + info!( "[{:?}] Synced {} out of {} finalized parentchain blocks", id, until_synced_header.number, curr_block_number, ); @@ -321,7 +321,7 @@ where shard, true, )?; - println!("[{:?}] synced block number: #{}", id, last_synced_header.number); + info!("[{:?}] synced block number: #{}", id, last_synced_header.number); std::thread::sleep(std::time::Duration::from_secs(1)); } Ok(last_synced_header) diff --git a/tee-worker/service/src/prometheus_metrics.rs b/tee-worker/service/src/prometheus_metrics.rs index cace3fbbcf..6d1b4d950c 100644 --- a/tee-worker/service/src/prometheus_metrics.rs +++ b/tee-worker/service/src/prometheus_metrics.rs @@ -317,8 +317,8 @@ fn assertion_to_string(assertion: Assertion) -> String { Assertion::TokenHoldingAmount(_) => "TokenHoldingAmount".into(), Assertion::PlatformUser(_) => "PlatformUser".into(), Assertion::NftHolder(_) => "NftHolder".into(), - Assertion::Dynamic(id, _) => { - format!("DynamicAssertion({:?})", id) + Assertion::Dynamic(param) => { + format!("DynamicAssertion({:?})", param.smart_contract_id) }, }; assertion diff --git a/tee-worker/service/src/setup.rs b/tee-worker/service/src/setup.rs index bc991992c4..35ec8715d9 100644 --- a/tee-worker/service/src/setup.rs +++ b/tee-worker/service/src/setup.rs @@ -18,8 +18,8 @@ use crate::error::{Error, ServiceResult}; use itp_settings::files::{ - ASSERTIONS_FILE, LITENTRY_PARENTCHAIN_LIGHT_CLIENT_DB_PATH, SCHEDULED_ENCLAVE_FILE, - SHARDS_PATH, SIDECHAIN_STORAGE_PATH, TARGET_A_PARENTCHAIN_LIGHT_CLIENT_DB_PATH, + ASSERTIONS_FILE, LITENTRY_PARENTCHAIN_LIGHT_CLIENT_DB_PATH, SHARDS_PATH, + SIDECHAIN_STORAGE_PATH, TARGET_A_PARENTCHAIN_LIGHT_CLIENT_DB_PATH, TARGET_B_PARENTCHAIN_LIGHT_CLIENT_DB_PATH, }; use std::{fs, path::Path}; @@ -76,23 +76,13 @@ mod needs_enclave { } } - pub(crate) fn migrate_shard( - enclave: &Enclave, - old_shard: &ShardIdentifier, - new_shard: &ShardIdentifier, - ) { - match enclave.migrate_shard(old_shard.encode(), new_shard.encode()) { + pub(crate) fn migrate_shard(enclave: &Enclave, &new_shard: &ShardIdentifier) { + match enclave.migrate_shard(new_shard.encode()) { Err(e) => { - println!( - "Failed to migrate old shard {:?} to new shard{:?}. {:?}", - old_shard, new_shard, e - ); + panic!("Failed to migrate shard {:?}. {:?}", new_shard, e); }, Ok(_) => { - println!( - "Successfully migrate old shard {:?} to new shard{:?}", - old_shard, new_shard - ); + println!("Shard {:?} migrated Successfully", new_shard); }, } } @@ -126,6 +116,17 @@ mod needs_enclave { } } +/// backs up shard directory and restores it after cleaning shards directory +pub(crate) fn remove_old_shards(root_dir: &Path, new_shard_name: &str) { + let shard_backup = root_dir.join("shard_backup"); + let shard_dir = root_dir.join(SHARDS_PATH).join(new_shard_name); + + fs::rename(shard_dir.clone(), shard_backup.clone()).expect("Failed to backup shard"); + remove_dir_if_it_exists(root_dir, SHARDS_PATH).expect("Failed to remove shards directory"); + fs::create_dir_all(root_dir.join(SHARDS_PATH)).expect("Failed to create shards directory"); + fs::rename(shard_backup, shard_dir).expect("Failed to restore shard"); +} + /// Purge all worker files from `dir`. pub(crate) fn purge_files_from_dir(dir: &Path) -> ServiceResult<()> { println!("[+] Performing a clean reset of the worker"); @@ -145,7 +146,6 @@ fn purge_files(root_directory: &Path) -> ServiceResult<()> { remove_dir_if_it_exists(root_directory, TARGET_A_PARENTCHAIN_LIGHT_CLIENT_DB_PATH)?; remove_dir_if_it_exists(root_directory, TARGET_B_PARENTCHAIN_LIGHT_CLIENT_DB_PATH)?; - remove_file_if_it_exists(root_directory, SCHEDULED_ENCLAVE_FILE)?; remove_file_if_it_exists(root_directory, ASSERTIONS_FILE)?; Ok(()) } @@ -219,6 +219,36 @@ mod tests { assert!(purge_files(&root_directory).is_ok()); } + #[test] + fn test_remove_old_shards() { + let test_directory_handle = TestDirectoryHandle::new(PathBuf::from("test_backup_shard")); + let root_directory = test_directory_handle.path(); + let new_shard_name = "new_shard"; + let old_shard_name = "old_shard"; + + let shard_1_dir = root_directory.join(SHARDS_PATH).join(new_shard_name); + fs::create_dir_all(&shard_1_dir).unwrap(); + fs::File::create(shard_1_dir.join("test_state.bin")).unwrap(); + fs::File::create(shard_1_dir.join("test_state_2.bin")).unwrap(); + + let shard_2_dir = root_directory.join(SHARDS_PATH).join(old_shard_name); + fs::create_dir_all(&shard_2_dir).unwrap(); + fs::File::create(shard_2_dir.join("test_state.bin")).unwrap(); + + assert!(root_directory.join(SHARDS_PATH).join(old_shard_name).exists()); + + remove_old_shards(root_directory, new_shard_name); + + assert!(root_directory.join(SHARDS_PATH).join(new_shard_name).exists()); + assert_eq!( + fs::read_dir(root_directory.join(SHARDS_PATH).join(new_shard_name)) + .expect("Failed to read shard directory") + .count(), + 2 + ); + assert!(!root_directory.join(SHARDS_PATH).join(old_shard_name).exists()); + } + /// Directory handle to automatically initialize a directory /// and upon dropping the reference, removing it again. struct TestDirectoryHandle { diff --git a/tee-worker/service/src/tests/mocks/enclave_api_mock.rs b/tee-worker/service/src/tests/mocks/enclave_api_mock.rs index 529bd50ebd..55e098c36b 100644 --- a/tee-worker/service/src/tests/mocks/enclave_api_mock.rs +++ b/tee-worker/service/src/tests/mocks/enclave_api_mock.rs @@ -101,7 +101,7 @@ impl EnclaveBase for EnclaveMock { Ok([1u8; MR_ENCLAVE_SIZE].into()) } - fn migrate_shard(&self, _old_shard: Vec, _new_shard: Vec) -> EnclaveResult<()> { + fn migrate_shard(&self, new_shard: Vec) -> EnclaveResult<()> { unimplemented!() } } diff --git a/tee-worker/sidechain/consensus/aura/Cargo.toml b/tee-worker/sidechain/consensus/aura/Cargo.toml index edb3ed9916..592de9293a 100644 --- a/tee-worker/sidechain/consensus/aura/Cargo.toml +++ b/tee-worker/sidechain/consensus/aura/Cargo.toml @@ -41,7 +41,6 @@ its-validateer-fetch = { path = "../../validateer-fetch", default-features = fal # litentry itp-utils = { path = "../../../core-primitives/utils", default-features = false } -lc-scheduled-enclave = { path = "../../../litentry/core/scheduled-enclave", default-features = false } litentry-hex-utils = { path = "../../../../primitives/hex", default-features = false } [dev-dependencies] @@ -84,7 +83,6 @@ std = [ "its-state/std", "its-validateer-fetch/std", "its-primitives/std", - "lc-scheduled-enclave/std", ] sgx = [ "sgx_tstd", @@ -102,5 +100,4 @@ sgx = [ "its-consensus-slots/sgx", "its-state/sgx", "its-block-verification/sgx", - "lc-scheduled-enclave/sgx", ] diff --git a/tee-worker/sidechain/consensus/aura/src/lib.rs b/tee-worker/sidechain/consensus/aura/src/lib.rs index 4114852c73..aa3f38a7da 100644 --- a/tee-worker/sidechain/consensus/aura/src/lib.rs +++ b/tee-worker/sidechain/consensus/aura/src/lib.rs @@ -33,10 +33,7 @@ use codec::Encode; use core::marker::PhantomData; use itc_parentchain_block_import_dispatcher::triggered_dispatcher::TriggerParentchainBlockImport; use itp_ocall_api::EnclaveOnChainOCallApi; -use itp_sgx_externalities::SgxExternalities; -use itp_stf_state_handler::handle_state::HandleState; use itp_time_utils::duration_now; - use its_block_verification::slot::slot_author; use its_consensus_common::{Environment, Error as ConsensusError, Proposer}; use its_consensus_slots::{SimpleSlotWorker, Slot, SlotInfo}; @@ -45,7 +42,6 @@ use its_primitives::{ types::block::BlockHash, }; use its_validateer_fetch::ValidateerFetch; -use lc_scheduled_enclave::ScheduledEnclaveUpdater; use litentry_hex_utils::hex_encode; use sp_core::crypto::UncheckedFrom; use sp_runtime::{ @@ -75,8 +71,6 @@ pub struct Aura< IntegriteeImportTrigger, TargetAImportTrigger, TargetBImportTrigger, - ScheduledEnclave, - StateHandler, > { authority_pair: AuthorityPair, ocall_api: OcallApi, @@ -85,8 +79,6 @@ pub struct Aura< maybe_parentchain_target_b_import_trigger: Option>, environment: Environment, claim_strategy: SlotClaimStrategy, - scheduled_enclave: Arc, - state_handler: Arc, _phantom: PhantomData<(AuthorityPair, ParentchainBlock, SidechainBlock)>, } @@ -99,8 +91,6 @@ impl< IntegriteeImportTrigger, TargetAImportTrigger, TargetBImportTrigger, - ScheduledEnclave, - StateHandler, > Aura< AuthorityPair, @@ -111,11 +101,8 @@ impl< IntegriteeImportTrigger, TargetAImportTrigger, TargetBImportTrigger, - ScheduledEnclave, - StateHandler, > { - #[allow(clippy::too_many_arguments)] pub fn new( authority_pair: AuthorityPair, ocall_api: OcallApi, @@ -123,8 +110,6 @@ impl< maybe_parentchain_target_a_import_trigger: Option>, maybe_parentchain_target_b_import_trigger: Option>, environment: Environment, - scheduled_enclave: Arc, - state_handler: Arc, ) -> Self { Self { authority_pair, @@ -134,8 +119,6 @@ impl< maybe_parentchain_target_b_import_trigger, environment, claim_strategy: SlotClaimStrategy::RoundRobin, - scheduled_enclave, - state_handler, _phantom: Default::default(), } } @@ -173,8 +156,6 @@ impl< IntegriteeImportTrigger, TargetAImportTrigger, TargetBImportTrigger, - ScheduledEnclave, - StateHandler, > SimpleSlotWorker for Aura< AuthorityPair, @@ -185,8 +166,6 @@ impl< IntegriteeImportTrigger, TargetAImportTrigger, TargetBImportTrigger, - ScheduledEnclave, - StateHandler, > where AuthorityPair: Pair, AuthorityPair::Public: UncheckedFrom<[u8; 32]>, @@ -202,23 +181,11 @@ impl< TriggerParentchainBlockImport>, TargetBImportTrigger: TriggerParentchainBlockImport>, - ScheduledEnclave: ScheduledEnclaveUpdater, - StateHandler: HandleState, { type Proposer = E::Proposer; type Claim = AuthorityPair::Public; type EpochData = Vec>; type Output = SignedSidechainBlock; - type ScheduledEnclave = ScheduledEnclave; - type StateHandler = StateHandler; - - fn get_scheduled_enclave(&mut self) -> Arc { - self.scheduled_enclave.clone() - } - - fn get_state_handler(&mut self) -> Arc { - self.state_handler.clone() - } fn epoch_data( &self, @@ -417,13 +384,12 @@ mod tests { }; use itc_parentchain_block_import_dispatcher::trigger_parentchain_block_import_mock::TriggerParentchainBlockImportMock; use itc_parentchain_test::{ParentchainBlockBuilder, ParentchainHeaderBuilder}; - use itp_test::mock::{handle_state_mock::HandleStateMock, onchain_mock::OnchainMock}; + use itp_test::mock::onchain_mock::OnchainMock; use itp_types::{ AccountId, Block as ParentchainBlock, Header as ParentchainHeader, ShardIdentifier, SignedBlock as SignedParentchainBlock, }; use its_consensus_slots::PerShardSlotWorkerScheduler; - use lc_scheduled_enclave::ScheduledEnclaveMock; use sp_core::ed25519::Public; use sp_keyring::ed25519::Keyring; @@ -438,8 +404,6 @@ mod tests { None, None, EnvironmentMock, - Arc::new(ScheduledEnclaveMock::default()), - Arc::new(HandleStateMock::from_shard(ShardIdentifier::default()).unwrap()), ) } @@ -454,8 +418,6 @@ mod tests { None, None, OutdatedBlockEnvironmentMock, - Arc::new(ScheduledEnclaveMock::default()), - Arc::new(HandleStateMock::from_shard(ShardIdentifier::default()).unwrap()), ) } diff --git a/tee-worker/sidechain/consensus/aura/src/slot_proposer.rs b/tee-worker/sidechain/consensus/aura/src/slot_proposer.rs index 8216fc371f..2424df56f6 100644 --- a/tee-worker/sidechain/consensus/aura/src/slot_proposer.rs +++ b/tee-worker/sidechain/consensus/aura/src/slot_proposer.rs @@ -196,8 +196,8 @@ impl< warn!("Failed to update metric for sidechain slot block composition time: {:?}", e); }; - println!( - "[Sidechain] propose block {} summary: executed {}, failed {}, from {} in queue in {}ms", + info!( + "Proposing sidechain block {} summary: executed {}, failed {}, from {} in queue in {}ms", sidechain_block.block().header().block_number(), number_executed_transactions, nr_failed_operations, diff --git a/tee-worker/sidechain/consensus/aura/src/test/fixtures/types.rs b/tee-worker/sidechain/consensus/aura/src/test/fixtures/types.rs index 80a5231829..040e812b12 100644 --- a/tee-worker/sidechain/consensus/aura/src/test/fixtures/types.rs +++ b/tee-worker/sidechain/consensus/aura/src/test/fixtures/types.rs @@ -26,7 +26,6 @@ use its_primitives::{ }, types::block::SignedBlock as SignedSidechainBlock, }; -use lc_scheduled_enclave::ScheduledEnclaveMock; use sp_runtime::{app_crypto::ed25519, generic::SignedBlock}; type AuthorityPair = ed25519::Pair; @@ -43,6 +42,4 @@ pub type TestAura = Aura< TriggerParentchainBlockImportMock>, TriggerParentchainBlockImportMock>, TriggerParentchainBlockImportMock>, - ScheduledEnclaveMock, - HandleStateMock, >; diff --git a/tee-worker/sidechain/consensus/common/src/block_import.rs b/tee-worker/sidechain/consensus/common/src/block_import.rs index 826b1e456b..e737901942 100644 --- a/tee-worker/sidechain/consensus/common/src/block_import.rs +++ b/tee-worker/sidechain/consensus/common/src/block_import.rs @@ -152,7 +152,7 @@ where let encrypted_state_diff = block_import_params.block().block_data().encrypted_state_diff(); - info!( + debug!( "Applying state diff for block {} of size {} bytes", block_number, encrypted_state_diff.len() @@ -166,7 +166,7 @@ where Ok(state) })?; - info!( + debug!( "Applying state update from block {} took {} ms", block_number, state_update_start_time.elapsed().as_millis() @@ -178,7 +178,7 @@ where self.get_context().store_sidechain_blocks(vec![signed_sidechain_block])?; let import_duration = start_time.elapsed(); - info!("Importing block {} took {} ms", block_number, import_duration.as_millis()); + debug!("Importing block {} took {} ms", block_number, import_duration.as_millis()); if let Err(e) = self .get_context() .update_metric(EnclaveMetric::SidechainBlockImportTime(import_duration)) diff --git a/tee-worker/sidechain/consensus/common/src/peer_block_sync.rs b/tee-worker/sidechain/consensus/common/src/peer_block_sync.rs index ed4d191bdb..481714a878 100644 --- a/tee-worker/sidechain/consensus/common/src/peer_block_sync.rs +++ b/tee-worker/sidechain/consensus/common/src/peer_block_sync.rs @@ -212,7 +212,7 @@ where _ => Err(e), }, Ok(latest_parentchain_header) => { - println!("[Sidechain] imported block (number: {}, tcalls: {}, author: {}), based on parentchain block {:?}", + info!("Imported sidechain block (number: {}, tcalls: {}, author: {}), based on parentchain block {:?}", sidechain_block_number, sidechain_block.block().block_data().signed_top_hashes().len(), hex_encode(sidechain_block.block().block_data().block_author().encode().as_slice()) ,latest_parentchain_header.number()); diff --git a/tee-worker/sidechain/consensus/slots/Cargo.toml b/tee-worker/sidechain/consensus/slots/Cargo.toml index 41070d0af0..d59fcd7db6 100644 --- a/tee-worker/sidechain/consensus/slots/Cargo.toml +++ b/tee-worker/sidechain/consensus/slots/Cargo.toml @@ -36,8 +36,6 @@ hex = { version = "0.4", default-features = false } itp-sgx-externalities = { path = "../../../core-primitives/substrate-sgx/externalities", default-features = false } itp-stf-state-handler = { path = "../../../core-primitives/stf-state-handler", default-features = false } its-state = { path = "../../state", default-features = false } -lc-scheduled-enclave = { path = "../../../litentry/core/scheduled-enclave", default-features = false } - [dev-dependencies] itc-parentchain-test = { path = "../../../core/parentchain/test" } @@ -65,7 +63,6 @@ std = [ "itp-stf-state-handler/std", "itp-sgx-externalities/std", "its-state/std", - "lc-scheduled-enclave/std", ] sgx = [ "itp-time-utils/sgx", @@ -74,5 +71,4 @@ sgx = [ "itp-stf-state-handler/sgx", "itp-sgx-externalities/sgx", "its-state/sgx", - "lc-scheduled-enclave/sgx", ] diff --git a/tee-worker/sidechain/consensus/slots/src/lib.rs b/tee-worker/sidechain/consensus/slots/src/lib.rs index b086a24ea2..c12d5ff0e4 100644 --- a/tee-worker/sidechain/consensus/slots/src/lib.rs +++ b/tee-worker/sidechain/consensus/slots/src/lib.rs @@ -34,8 +34,6 @@ extern crate sgx_tstd as std; use codec::Encode; use core::str::FromStr; use derive_more::From; -use itp_sgx_externalities::SgxExternalities; -use itp_stf_state_handler::handle_state::HandleState; use itp_time_utils::{duration_difference, duration_now}; use its_consensus_common::{Error as ConsensusError, Proposer}; @@ -43,12 +41,10 @@ use its_primitives::traits::{ Block as SidechainBlockTrait, Header as HeaderTrait, ShardIdentifierFor, SignedBlock as SignedSidechainBlockTrait, }; -use its_state::SidechainSystemExt; -use lc_scheduled_enclave::ScheduledEnclaveUpdater; use log::*; pub use slots::*; use sp_runtime::traits::{Block as ParentchainBlockTrait, Header as ParentchainHeaderTrait}; -use std::{fmt::Debug, sync::Arc, time::Duration, vec::Vec}; +use std::{fmt::Debug, time::Duration, vec::Vec}; #[cfg(feature = "std")] mod slot_stream; @@ -189,18 +185,6 @@ pub trait SimpleSlotWorker { /// Output generated after a slot type Output: SignedSidechainBlockTrait + Send + 'static; - /// Scheduled enclave context for authoring - type ScheduledEnclave: ScheduledEnclaveUpdater; - - /// State handler context for authoring - type StateHandler: HandleState; - - /// Get scheduled enclave - fn get_scheduled_enclave(&mut self) -> Arc; - - /// Get state handler for query and mutation - fn get_state_handler(&mut self) -> Arc; - /// Returns the epoch data necessary for authoring. For time-dependent epochs, /// use the provided slot number as a canonical source of time. fn epoch_data( @@ -347,35 +331,6 @@ pub trait SimpleSlotWorker { debug!("Skipping proposal slot. Authorities len {:?}", authorities_len); } - // Return early if MRENCLAVE doesn't match - it implies that the enclave should be updated - let scheduled_enclave = self.get_scheduled_enclave(); - let state_handler = self.get_state_handler(); - // TODO: is this always consistent? Reference: `propose_state_update` in slot_proposer.rs - let (state, _) = state_handler.load_cloned(&shard.into()).ok()?; - let next_sidechain_number = state.get_block_number().map_or(1, |n| n + 1); - - if !scheduled_enclave.is_mrenclave_matching(next_sidechain_number) { - warn!( - "Skipping sidechain block {} due to mismatch MRENCLAVE, current: {:?}, expect: {:?}", - next_sidechain_number, - scheduled_enclave.get_current_mrenclave().map(hex::encode), - scheduled_enclave.get_expected_mrenclave(next_sidechain_number).map(hex::encode), - ); - if let Ok(false) = scheduled_enclave.is_block_production_paused() { - let _ = scheduled_enclave.set_block_production_paused(true); - info!("Pause sidechain block production"); - } - return None - } else { - // TODO: this block production pause/unpause is not strictly needed but I add it here as placeholder. - // Maybe we should add a field to describe the reason for pausing/unpausing, as - // it's possible that we want to manually/focibly pause the sidechain - if let Ok(true) = scheduled_enclave.is_block_production_paused() { - info!("Resume sidechain block production"); - let _ = scheduled_enclave.set_block_production_paused(false); - } - } - // TODO: about the shard migration and state migration // - the shard migration(copy-over) is done manually by the subcommand "migrate-shard". // - the state migration is done via conditionally calling on_runtime_upgrade() by comparing @@ -401,7 +356,7 @@ pub trait SimpleSlotWorker { }; trace!( "on_slot: a posteriori latest Litentry block number (if there is a new one): {:?}", - last_imported_integritee_header.clone().map(|h| *h.number()) + last_imported_integritee_header.map(|h| *h.number()) ); let maybe_last_imported_target_a_header = @@ -466,7 +421,7 @@ pub trait SimpleSlotWorker { }; if is_single_worker { - warn!("Running as single worker, skipping timestamp within slot check") + debug!("Running as single worker, skipping timestamp within slot check") } else if !timestamp_within_slot(&slot_info, &proposing.block) { warn!( "⌛️ Discarding proposal for slot {}, block number {}; block production took too long", @@ -476,19 +431,10 @@ pub trait SimpleSlotWorker { return None } - if last_imported_integritee_header.is_some() { - println!( - "Syncing Parentchains: Litentry: {:?} TargetA: {:?}, TargetB: {:?}, Sidechain: {:?}", - latest_integritee_parentchain_header.number(), - maybe_latest_target_a_parentchain_header.map(|h| *h.number()), - maybe_latest_target_b_parentchain_header.map(|h| *h.number()), - proposing.block.block().header().block_number() - ); - } - - info!("Proposing sidechain block (number: {}, hash: {}) based on integritee parentchain block (number: {:?}, hash: {:?})", - proposing.block.block().header().block_number(), proposing.block.hash(), - latest_integritee_parentchain_header.number(), latest_integritee_parentchain_header.hash() + info!( + "Proposed sidechain block {} based on parentchain block {:?}", + proposing.block.block().header().block_number(), + latest_integritee_parentchain_header.number() ); Some(SlotResult { diff --git a/tee-worker/sidechain/consensus/slots/src/mocks.rs b/tee-worker/sidechain/consensus/slots/src/mocks.rs index 72d6f9fee8..971ee1c942 100644 --- a/tee-worker/sidechain/consensus/slots/src/mocks.rs +++ b/tee-worker/sidechain/consensus/slots/src/mocks.rs @@ -19,7 +19,6 @@ use crate::{slots::Slot, SimpleSlotWorker, SlotInfo, SlotResult}; pub use itp_test::mock::handle_state_mock::HandleStateMock; use its_consensus_common::{Proposal, Proposer, Result}; use its_primitives::{traits::ShardIdentifierFor, types::SignedBlock as SignedSidechainBlock}; -use lc_scheduled_enclave::ScheduledEnclaveMock; use sp_runtime::traits::{Block as ParentchainBlockTrait, Header as ParentchainHeaderTrait}; use std::{marker::PhantomData, sync::Arc, thread, time::Duration}; @@ -58,18 +57,6 @@ where type Output = SignedSidechainBlock; - type ScheduledEnclave = ScheduledEnclaveMock; - - type StateHandler = HandleStateMock; - - fn get_scheduled_enclave(&mut self) -> Arc { - todo!() - } - - fn get_state_handler(&mut self) -> Arc { - todo!() - } - fn epoch_data(&self, _header: &B::Header, _slot: Slot) -> Result { todo!() } diff --git a/tee-worker/sidechain/rpc-handler/src/import_block_api.rs b/tee-worker/sidechain/rpc-handler/src/import_block_api.rs index a34ff829ef..fd8ab733a1 100644 --- a/tee-worker/sidechain/rpc-handler/src/import_block_api.rs +++ b/tee-worker/sidechain/rpc-handler/src/import_block_api.rs @@ -49,7 +49,7 @@ where debug!("{}. Blocks: {:?}", RPC_METHOD_NAME_IMPORT_BLOCKS, blocks); for block in blocks { - info!("Add block {} to import queue", block.block.header.block_number); + debug!("Add sidechain block {} to import queue", block.block.header.block_number); let _ = import_fn(block).map_err(|e| { let error = jsonrpc_core::error::Error::invalid_params_with_details( "Failed to import Block.", diff --git a/tee-worker/sidechain/state/src/impls.rs b/tee-worker/sidechain/state/src/impls.rs index b69727085c..d52e838c9d 100644 --- a/tee-worker/sidechain/state/src/impls.rs +++ b/tee-worker/sidechain/state/src/impls.rs @@ -23,7 +23,7 @@ use core::fmt::Debug; use frame_support::ensure; use itp_sgx_externalities::{SgxExternalitiesTrait, StateHash}; use itp_storage::keys::storage_value_key; -use log::{debug, error, info}; +use log::*; use sp_io::{storage, KillStorageResult}; impl SidechainState for T @@ -34,7 +34,7 @@ where type StateUpdate = StateUpdate; fn apply_state_update(&mut self, state_payload: &Self::StateUpdate) -> Result<(), Error> { - info!("Current state size: {}", self.state().encoded_size()); + debug!("Current state size: {}", self.state().encoded_size()); debug!("Current hash: {}", self.hash()); debug!("State_payload hash: {}", state_payload.state_hash_apriori()); debug!("self is: {:?}", &self); diff --git a/tee-worker/ts-tests/.gitignore b/tee-worker/ts-tests/.gitignore index 3a8fe5ede8..a03a0421d5 100644 --- a/tee-worker/ts-tests/.gitignore +++ b/tee-worker/ts-tests/.gitignore @@ -1 +1,4 @@ -.env.local \ No newline at end of file +.env.local +contracts/ +contracts-build-info/ +cache/ \ No newline at end of file diff --git a/tee-worker/ts-tests/README.md b/tee-worker/ts-tests/README.md index 0d52a8a472..8ac6abfdc0 100644 --- a/tee-worker/ts-tests/README.md +++ b/tee-worker/ts-tests/README.md @@ -53,4 +53,16 @@ Direct invocation vc test: `pnpm --filter integration-tests run test di_vc.test. 1. Single test: `pnpm run test-data-providers:local --id=your credential json id` 2. All credential tests:`pnpm run test-data-providers:local`(Run all the `credential-json/*.json` test cases, execute them in the order of [export](https://github.com/litentry/litentry-parachain/blob/dev/tee-worker/ts-tests/integration-tests/common/credential-json/index.ts#L21).) -​ \ No newline at end of file +## Assertion contracts tests + +- Install [foundry](https://book.getfoundry.sh/getting-started/installation) +- Copy [assertion contracts](https://github.com/litentry/litentry-parachain/tree/dev/tee-worker/litentry/core/assertion-build/src/dynamic/contracts) to the ts-tests directory(ts-tests folder): + `pnpm --filter integration-tests run cp-contracts` +- Compile contracts using foundry(ts-tests folder): + `pnpm --filter integration-tests run compile-contracts` +- Perform testing: + `pnpm --filter integration-tests run test assertion_contracts.test.ts` + +##### How to update the OpenZeppelin library for assertion contracts? + +If using the Strings.sol library of v4.9.0, just go to the [link](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.0/contracts/utils/Strings.sol), then copy the entire contract code(include releated contracts). It is best to maintain the same directory structure. If you want to update versions, for example, if you want to update version v5.0.0, just copy and replace the current libraries code with the v5.0.0 libraries code. \ No newline at end of file diff --git a/tee-worker/ts-tests/integration-tests/assertion_contracts.test.ts b/tee-worker/ts-tests/integration-tests/assertion_contracts.test.ts new file mode 100644 index 0000000000..2237e239ba --- /dev/null +++ b/tee-worker/ts-tests/integration-tests/assertion_contracts.test.ts @@ -0,0 +1,157 @@ +import { randomBytes, KeyObject } from 'crypto'; +import { step } from 'mocha-steps'; +import { buildValidations, initIntegrationTestContext } from './common/utils'; +import { assertIsInSidechainBlock, assertVc } from './common/utils/assertion'; +import { + getSidechainNonce, + getTeeShieldingKey, + sendRequestFromTrustedCall, + createSignedTrustedCallRequestVc, + createSignedTrustedCallLinkIdentity, +} from './common/di-utils'; // @fixme move to a better place +import type { IntegrationTestContext } from './common/common-types'; +import { aesKey } from './common/call'; +import type { CorePrimitivesIdentity, LitentryValidationData, Web3Network } from 'parachain-api'; +import fs from 'fs'; +import path from 'path'; +import { assert } from 'chai'; +import { genesisSubstrateWallet } from './common/helpers'; +import { KeyringPair } from '@polkadot/keyring/types'; +import { subscribeToEvents } from './common/transactions'; +import { encryptWithTeeShieldingKey } from './common/utils/crypto'; +import { ethers } from 'ethers'; +import { sleep } from './common/utils'; +import { Bytes, Vec } from '@polkadot/types-codec'; + +describe('Test Vc (direct request)', function () { + let context: IntegrationTestContext = undefined as any; + let teeShieldingKey: KeyObject = undefined as any; + let aliceSubstrateIdentity: CorePrimitivesIdentity = undefined as any; + + let alice: KeyringPair = undefined as any; + let contractBytecode = undefined as any; + const linkIdentityRequestParams: { + nonce: number; + identity: CorePrimitivesIdentity; + validation: LitentryValidationData; + networks: Bytes | Vec; + }[] = []; + this.timeout(6000000); + + before(async () => { + context = await initIntegrationTestContext( + process.env.WORKER_ENDPOINT!, // @fixme evil assertion; centralize env access + process.env.NODE_ENDPOINT! // @fixme evil assertion; centralize env access + ); + teeShieldingKey = await getTeeShieldingKey(context); + aliceSubstrateIdentity = await context.web3Wallets.substrate.Alice.getIdentity(context); + alice = genesisSubstrateWallet('Alice'); + }); + + step('loading tokenmapping contract bytecode', async function () { + const file = path.resolve('./', './contracts-build-info/TokenMapping.sol/TokenMapping.json'); + const data = fs.readFileSync(file, 'utf8'); + contractBytecode = JSON.parse(data).bytecode.object; + assert.isNotEmpty(contractBytecode); + }); + + step('deploying tokenmapping contract via parachain pallet', async function () { + const secretValue = 'my-secrets-value'; + const secretEncoded = context.api.createType('String', secretValue).toU8a(); + const encryptedSecrets = encryptWithTeeShieldingKey(teeShieldingKey, secretEncoded); + + const secret = '0x' + encryptedSecrets.toString('hex'); + + const assertionId = '0x0000000000000000000000000000000000000003'; + const createAssertionEventsPromise = subscribeToEvents('evmAssertions', 'AssertionCreated', context.api); + + const proposal = context.api.tx.evmAssertions.createAssertion(assertionId, contractBytecode, [secret]); + await context.api.tx.developerCommittee.execute(proposal, proposal.encodedLength).signAndSend(alice); + + const event = (await createAssertionEventsPromise).map((e) => e); + assert.equal(event.length, 1); + }); + + step('linking identities (alice)', async function () { + let currentNonce = (await getSidechainNonce(context, aliceSubstrateIdentity)).toNumber(); + const getNextNonce = () => currentNonce++; + const evmNonce = getNextNonce(); + + const evmIdentity = await context.web3Wallets.evm.Alice.getIdentity(context); + const evmValidation = await buildValidations( + context, + aliceSubstrateIdentity, + evmIdentity, + evmNonce, + 'ethereum', + context.web3Wallets.evm.Alice + ); + const evmNetworks = context.api.createType('Vec', ['Ethereum', 'Bsc']); + linkIdentityRequestParams.push({ + nonce: evmNonce, + identity: evmIdentity, + validation: evmValidation, + networks: evmNetworks, + }); + + let counter = 0; + for (const { nonce, identity, validation, networks } of linkIdentityRequestParams) { + counter++; + const requestIdentifier = `0x${randomBytes(32).toString('hex')}`; + const linkIdentityCall = await createSignedTrustedCallLinkIdentity( + context.api, + context.mrEnclave, + context.api.createType('Index', nonce), + context.web3Wallets.substrate.Alice, + aliceSubstrateIdentity, + identity.toHex(), + validation.toHex(), + networks.toHex(), + context.api.createType('Option', aesKey).toHex(), + requestIdentifier, + { + withWrappedBytes: false, + withPrefix: counter % 2 === 0, // alternate per entry + } + ); + + const res = await sendRequestFromTrustedCall(context, teeShieldingKey, linkIdentityCall); + await assertIsInSidechainBlock('linkIdentityCall', res); + } + }); + + step('requesting VC for deployed contract', async function () { + await sleep(30); + const requestIdentifier = `0x${randomBytes(32).toString('hex')}`; + const nonce = (await getSidechainNonce(context, aliceSubstrateIdentity)).toNumber(); + + const abiCoder = new ethers.utils.AbiCoder(); + const encodedData = abiCoder.encode(['string'], ['bnb']); + const assertion = { + dynamic: context.api.createType('DynamicParams', [ + Uint8Array.from(Buffer.from('0000000000000000000000000000000000000003', 'hex')), + encodedData, + false, + ]), + }; + + const requestVcCall = await createSignedTrustedCallRequestVc( + context.api, + context.mrEnclave, + context.api.createType('Index', nonce), + context.web3Wallets.substrate.Alice, + aliceSubstrateIdentity, + context.api.createType('Assertion', assertion).toHex(), + context.api.createType('Option', aesKey).toHex(), + requestIdentifier, + { + withWrappedBytes: false, + withPrefix: true, + } + ); + + const res = await sendRequestFromTrustedCall(context, teeShieldingKey, requestVcCall); + await assertIsInSidechainBlock(`${Object.keys(assertion)[0]} requestVcCall`, res); + assertVc(context, aliceSubstrateIdentity, res.value); + }); +}); diff --git a/tee-worker/ts-tests/integration-tests/common/utils/assertion.ts b/tee-worker/ts-tests/integration-tests/common/utils/assertion.ts index a61bcba360..c0c50164c6 100644 --- a/tee-worker/ts-tests/integration-tests/common/utils/assertion.ts +++ b/tee-worker/ts-tests/integration-tests/common/utils/assertion.ts @@ -148,7 +148,7 @@ export async function assertVc(context: IntegrationTestContext, subject: CorePri // check runtime version is present assert.deepEqual( vcPayloadJson.issuer.runtimeVersion, - { parachain: 9181, sidechain: 108 }, + { parachain: 9184, sidechain: 109 }, 'Check VC runtime version: it should equal the current defined versions' ); diff --git a/tee-worker/ts-tests/integration-tests/common/utils/identity-helper.ts b/tee-worker/ts-tests/integration-tests/common/utils/identity-helper.ts index 952793f587..35871fb8c2 100644 --- a/tee-worker/ts-tests/integration-tests/common/utils/identity-helper.ts +++ b/tee-worker/ts-tests/integration-tests/common/utils/identity-helper.ts @@ -14,13 +14,21 @@ export function generateVerificationMessage( context: IntegrationTestContext, signer: CorePrimitivesIdentity, identity: CorePrimitivesIdentity, - sidechainNonce: number -): HexString { + sidechainNonce: number, + options?: { prettifiedMessage?: boolean } +): string { + const _options = { prettifiedMessage: false, ...options }; const encodedIdentity = context.api.createType('CorePrimitivesIdentity', identity).toU8a(); const encodedWho = context.api.createType('CorePrimitivesIdentity', signer).toU8a(); const encodedSidechainNonce = context.api.createType('Index', sidechainNonce); const msg = Buffer.concat([encodedSidechainNonce.toU8a(), encodedWho, encodedIdentity]); - return blake2AsHex(msg, 256); + const hash = blake2AsHex(msg, 256); + + if (_options.prettifiedMessage) { + return `Token: ${hash}`; + } + + return hash; } export async function buildIdentityHelper( @@ -139,8 +147,10 @@ export async function buildValidations( linkIdentity: CorePrimitivesIdentity, startingSidechainNonce: number, network: 'ethereum' | 'substrate' | 'bitcoin' | 'solana', - signer?: Signer + signer?: Signer, + options?: { prettifiedMessage?: boolean } ): Promise { + const _options = { prettifiedMessage: false, ...options }; const validationNonce = startingSidechainNonce++; const msg = generateVerificationMessage(context, signerIdentitity, linkIdentity, validationNonce); @@ -148,7 +158,7 @@ export async function buildValidations( const evmValidationData = { Web3Validation: { Evm: { - message: '' as HexString, + message: '', signature: { Ethereum: '' as HexString, }, @@ -168,7 +178,7 @@ export async function buildValidations( const substrateValidationData = { Web3Validation: { Substrate: { - message: '' as HexString, + message: '', signature: { Sr25519: '' as HexString, }, @@ -187,7 +197,7 @@ export async function buildValidations( const bitcoinValidationData = { Web3Validation: { Bitcoin: { - message: '' as HexString, + message: '', signature: { Bitcoin: '' as HexString, }, @@ -206,7 +216,7 @@ export async function buildValidations( const solanaValidationData = { Web3Validation: { Solana: { - message: '' as HexString, + message: '', signature: { Ed25519: '' as HexString, }, diff --git a/tee-worker/ts-tests/integration-tests/common/utils/vc-helper.ts b/tee-worker/ts-tests/integration-tests/common/utils/vc-helper.ts index e0b4a6c562..2c3f4daf5b 100644 --- a/tee-worker/ts-tests/integration-tests/common/utils/vc-helper.ts +++ b/tee-worker/ts-tests/integration-tests/common/utils/vc-helper.ts @@ -216,6 +216,18 @@ export const mockAssertions = [ NftHolder: 'Club3Sbt', }, }, + { + description: 'You are a holder of a certain kind of NFT', + assertion: { + NftHolder: 'MFan', + }, + }, + { + description: 'You are a holder of a certain kind of NFT', + assertion: { + NftHolder: 'Mvp', + }, + }, // TokenHoldingAmount { @@ -272,6 +284,18 @@ export const mockAssertions = [ TokenHoldingAmount: 'BEAN', }, }, + { + description: 'The amount of AN you are holding', + assertion: { + TokenHoldingAmount: 'AN', + }, + }, + { + description: 'The amount of TUNA you are holding', + assertion: { + TokenHoldingAmount: 'TUNA', + }, + }, { description: 'The amount of LIT you are staking', @@ -288,15 +312,21 @@ export const mockAssertions = [ // PlatformUser { - description: 'You are a user of a certain platform', + description: 'You are a user of platform KaratDao', + assertion: { + PlatformUser: 'KaratDao', + }, + }, + { + description: 'You are a user of platform MagicCraft', assertion: { - PlatformUser: 'KaratDaoUser', + PlatformUser: 'MagicCraftStaking', }, }, { - description: 'You are a user of a certain platform', + description: 'You are a user of platform DarenMarket', assertion: { - PlatformUser: 'MagicCraftStakingUser', + PlatformUser: 'DarenMarket', }, }, diff --git a/tee-worker/ts-tests/integration-tests/di_bitcoin_identity.test.ts b/tee-worker/ts-tests/integration-tests/di_bitcoin_identity.test.ts index 50a83aa3aa..9df232d003 100644 --- a/tee-worker/ts-tests/integration-tests/di_bitcoin_identity.test.ts +++ b/tee-worker/ts-tests/integration-tests/di_bitcoin_identity.test.ts @@ -107,7 +107,8 @@ describe('Test Identity (bitcoin direct invocation)', function () { bobBitcoinIdentity, bobBitcoinNonce, 'bitcoin', - context.web3Wallets.bitcoin.Bob + context.web3Wallets.bitcoin.Bob, + { prettifiedMessage: true } ); const bobBitcoinNetowrks = context.api.createType('Vec', ['BitcoinP2tr']); linkIdentityRequestParams.push({ diff --git a/tee-worker/ts-tests/integration-tests/di_evm_identity.test.ts b/tee-worker/ts-tests/integration-tests/di_evm_identity.test.ts index babcbe012b..fc897e6a74 100644 --- a/tee-worker/ts-tests/integration-tests/di_evm_identity.test.ts +++ b/tee-worker/ts-tests/integration-tests/di_evm_identity.test.ts @@ -79,7 +79,8 @@ describe('Test Identity (evm direct invocation)', function () { bobEvmIdentity, bobEvmNonce, 'ethereum', - context.web3Wallets.evm.Bob + context.web3Wallets.evm.Bob, + { prettifiedMessage: true } ); const bobEvmNetworks = context.api.createType('Vec', ['Ethereum', 'Bsc']); linkIdentityRequestParams.push({ diff --git a/tee-worker/ts-tests/integration-tests/di_solana_identity.test.ts b/tee-worker/ts-tests/integration-tests/di_solana_identity.test.ts index af5034d3eb..f625b16858 100644 --- a/tee-worker/ts-tests/integration-tests/di_solana_identity.test.ts +++ b/tee-worker/ts-tests/integration-tests/di_solana_identity.test.ts @@ -77,7 +77,8 @@ describe('Test Identity (solana direct invocation)', function () { bobSolanaIdentity, bobSolanaNonce, 'solana', - context.web3Wallets.solana.Bob + context.web3Wallets.solana.Bob, + { prettifiedMessage: true } ); const bobSolanaNetworks = context.api.createType('Vec', ['Solana']); linkIdentityRequestParams.push({ diff --git a/tee-worker/ts-tests/integration-tests/di_substrate_identity.test.ts b/tee-worker/ts-tests/integration-tests/di_substrate_identity.test.ts index 75fa2bbe67..55fe4cc4b8 100644 --- a/tee-worker/ts-tests/integration-tests/di_substrate_identity.test.ts +++ b/tee-worker/ts-tests/integration-tests/di_substrate_identity.test.ts @@ -134,7 +134,8 @@ describe('Test Identity (direct invocation)', function () { eveSubstrateIdentity, eveSubstrateNonce, 'substrate', - context.web3Wallets.substrate.Eve + context.web3Wallets.substrate.Eve, + { prettifiedMessage: true } ); const eveSubstrateNetworks = context.api.createType('Vec', ['Polkadot', 'Litentry']); linkIdentityRequestParams.push({ diff --git a/tee-worker/ts-tests/integration-tests/foundry.toml b/tee-worker/ts-tests/integration-tests/foundry.toml new file mode 100644 index 0000000000..89ec405f5a --- /dev/null +++ b/tee-worker/ts-tests/integration-tests/foundry.toml @@ -0,0 +1,4 @@ +[default] +src='contracts' +out='contracts-build-info' +solc_version='0.8.11' \ No newline at end of file diff --git a/tee-worker/ts-tests/integration-tests/package.json b/tee-worker/ts-tests/integration-tests/package.json index 478d60c69b..2301308562 100644 --- a/tee-worker/ts-tests/integration-tests/package.json +++ b/tee-worker/ts-tests/integration-tests/package.json @@ -7,7 +7,9 @@ "format": "prettier --write .", "pretest": "eslint .", "test": "mocha --exit --sort -r ts-node/register --loader=ts-node/esm", - "check-types": "tsc --noEmit" + "check-types": "tsc --noEmit", + "copy-contracts": "cp -r ../../litentry/core/assertion-build/src/dynamic/contracts ./contracts", + "compile-contracts": "forge build" }, "dependencies": { "@litentry/vc-schema-validator": "^0.0.1", diff --git a/tee-worker/ts-tests/integration-tests/scheduled_enclave.test.ts b/tee-worker/ts-tests/integration-tests/scheduled_enclave.test.ts deleted file mode 100644 index b50b13641a..0000000000 --- a/tee-worker/ts-tests/integration-tests/scheduled_enclave.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { KeyObject } from 'crypto'; -import { step } from 'mocha-steps'; -import { initIntegrationTestContext } from './common/utils'; -import { getTeeShieldingKey } from './common/di-utils'; -import type { IntegrationTestContext, JsonRpcRequest } from './common/common-types'; -import { sendRequest } from './common/call'; -import { type CorePrimitivesIdentity } from 'parachain-api'; -import { assert } from 'chai'; -import { createJsonRpcRequest, nextRequestId } from './common/helpers'; -import { setAliceAsAdmin, setScheduledEnclave, waitForBlock } from './common/transactions'; - -describe('Scheduled Enclave', function () { - let context: IntegrationTestContext; - let teeShieldingKey: KeyObject; - let aliceSubstrateIdentity: CorePrimitivesIdentity; - - this.timeout(6000000); - - before(async () => { - context = await initIntegrationTestContext( - process.env.WORKER_ENDPOINT!, // @fixme evil assertion; centralize env access - process.env.NODE_ENDPOINT! // @fixme evil assertion; centralize env access - ); - teeShieldingKey = await getTeeShieldingKey(context); - aliceSubstrateIdentity = await context.web3Wallets.substrate.Alice.getIdentity(context); - await setAliceAsAdmin(context.api); - }); - - step('state of scheduled enclave list', async function () { - const request = createJsonRpcRequest('state_getScheduledEnclave', undefined, nextRequestId(context)); - const response = await sendRequest(context.tee, request, context.api); - const scheduledEnclaveList = context.api.createType('Vec<(u64, [u8; 32])>', response.value).toJSON() as [ - number, - string - ][]; - - assert.equal(1, scheduledEnclaveList.length); - - const [blockNumber, mrEnclave] = scheduledEnclaveList[0]; - assert.equal(blockNumber, 0); - assert.equal(mrEnclave, context.mrEnclave); - }); - - step('setting new scheduled enclave', async function () { - const buildRequest = (method: string, params?: any[]) => - createJsonRpcRequest(method, params, nextRequestId(context)); - const callRPC = async (request: JsonRpcRequest) => sendRequest(context.tee, request, context.api); - - let response = await callRPC(buildRequest('state_getScheduledEnclave')); - let scheduledEnclaveList = context.api.createType('Vec<(u64, [u8; 32])>', response.value).toJSON() as [ - number, - string - ][]; - - assert.equal(scheduledEnclaveList.length, 1, 'Initial number of enclave should be 1'); - - // set new mrenclave - const lastBlock = await context.api.rpc.chain.getBlock(); - const expectedBlockNumber = lastBlock.block.header.number.toNumber() + 5; - console.log(`expected mrenclave block number: ${expectedBlockNumber}`); - - const validMrEnclave = '97f516a61ff59c5eab74b8a9b1b7273d6986b9c0e6c479a4010e22402ca7cee6'; - - await setScheduledEnclave(context.api, expectedBlockNumber, validMrEnclave); - const timeSpanForWorkersSync = 2; - await waitForBlock(context.api, expectedBlockNumber + timeSpanForWorkersSync); - - response = await callRPC(buildRequest('state_getScheduledEnclave')); - scheduledEnclaveList = context.api.createType('Vec<(u64, [u8; 32])>', response.value).toJSON() as [ - number, - string - ][]; - - assert.equal(scheduledEnclaveList.length, 2); - - const [blockNumber, mrEnclave] = scheduledEnclaveList[1]; - assert.equal(blockNumber, expectedBlockNumber); - assert.equal(mrEnclave, `0x${validMrEnclave}`); - }); -});