diff --git a/.github/workflows/test-suite-e2e-tests.yml b/.github/workflows/test-suite-e2e-tests.yml index 0d2662283..125b65cc1 100644 --- a/.github/workflows/test-suite-e2e-tests.yml +++ b/.github/workflows/test-suite-e2e-tests.yml @@ -182,6 +182,63 @@ jobs: run: | ./fhevm-cli test public-decrypt-http-mixed + # E2E tests on pausing the Gateway contracts + - name: Pause Gateway Contracts + working-directory: test-suite/fhevm + run: | + ./fhevm-cli pause gateway + + - name: Paused Gateway input proof test (uint64) + working-directory: test-suite/fhevm + run: | + ./fhevm-cli test paused-gateway-input-proof + + - name: Paused Gateway user decryption test + working-directory: test-suite/fhevm + run: | + ./fhevm-cli test paused-gateway-user-decryption + + - name: Paused Gateway public decryption HTTP endpoint test + working-directory: test-suite/fhevm + run: | + ./fhevm-cli test paused-gateway-public-decrypt-http + + - name: Unpause Gateway Contracts + working-directory: test-suite/fhevm + run: | + ./fhevm-cli unpause gateway + + # E2E tests after unpausing the Gateway contracts + - name: Input proof test (uint64) + working-directory: test-suite/fhevm + run: | + ./fhevm-cli test input-proof + + - name: Input proof test with compute and decrypt (uint64) + working-directory: test-suite/fhevm + run: | + ./fhevm-cli test input-proof-compute-decrypt + + - name: User Decryption test + working-directory: test-suite/fhevm + run: | + ./fhevm-cli test user-decryption + + - name: ERC20 test + working-directory: test-suite/fhevm + run: | + ./fhevm-cli test erc20 + + - name: Public Decryption HTTP endpoint test (ebool) + working-directory: test-suite/fhevm + run: | + ./fhevm-cli test public-decrypt-http-ebool + + - name: Public Decryption HTTP endpoint test (mixed) + working-directory: test-suite/fhevm + run: | + ./fhevm-cli test public-decrypt-http-mixed + - name: Show logs on test failure working-directory: test-suite/fhevm if: always() diff --git a/test-suite/e2e/test/pausedProtocol/pausedGateway.ts b/test-suite/e2e/test/pausedProtocol/pausedGateway.ts new file mode 100644 index 000000000..70ff844b6 --- /dev/null +++ b/test-suite/e2e/test/pausedProtocol/pausedGateway.ts @@ -0,0 +1,68 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { createInstances } from '../instance'; +import { getSigners, initSigners } from '../signers'; +import { userDecryptSingleHandle } from '../utils'; + +describe('Paused gateway', function () { + before(async function () { + await initSigners(2); + this.signers = await getSigners(); + this.instances = await createInstances(this.signers); + + // Initialize TestInput contract. + const testInputContractFactory = await ethers.getContractFactory('TestInput'); + this.testInputContract = await testInputContractFactory.connect(this.signers.alice).deploy(); + this.testInputContractAddress = await this.testInputContract.getAddress(); + await this.testInputContract.waitForDeployment(); + + // Initialize UserDecrypt contract. + const userDecryptContractFactory = await ethers.getContractFactory('UserDecrypt'); + this.userDecryptContract = await userDecryptContractFactory.connect(this.signers.alice).deploy(); + await this.userDecryptContract.waitForDeployment(); + this.userDecryptContractAddress = await this.userDecryptContract.getAddress(); + + // Initialize HTTPPublicDecrypt contract. + const httpPublicDecryptContractFactory = await ethers.getContractFactory('HTTPPublicDecrypt'); + this.httpPublicDecryptContract = await httpPublicDecryptContractFactory.connect(this.signers.alice).deploy(); + await this.httpPublicDecryptContract.waitForDeployment(); + }); + + // InputVerification tests. + it('test paused gateway user input uint64 (non-trivial)', async function () { + const inputAlice = this.instances.alice.createEncryptedInput( + this.testInputContractAddress, + this.signers.alice.address, + ); + inputAlice.add64(18446744073709550042n); + + await expect(inputAlice.encrypt()).to.be.rejectedWith(new RegExp('Input request failed')); + }); + + // UserDecryption tests. + it('test paused gateway user decrypt', async function () { + const handle = await this.userDecryptContract.xBool(); + const { publicKey, privateKey } = this.instances.alice.generateKeypair(); + await expect( + userDecryptSingleHandle( + handle, + this.userDecryptContractAddress, + this.instances.alice, + this.signers.alice, + privateKey, + publicKey, + ), + ).to.be.rejectedWith(new RegExp('User decrypt failed')); + }); + + // PublicDecryption tests. + it('test paused gateway HTTPPublicDecrypt', async function () { + const handleBool = await this.httpPublicDecryptContract.xBool(); + const handleAddress = await this.httpPublicDecryptContract.xAddress(); + const handle32 = await this.httpPublicDecryptContract.xUint32(); + await expect(this.instances.alice.publicDecrypt([handleAddress, handle32, handleBool])).to.be.rejectedWith( + new RegExp('Public decrypt failed'), + ); + }); +}); diff --git a/test-suite/fhevm/docker-compose/gateway-pause-docker-compose.yml b/test-suite/fhevm/docker-compose/gateway-pause-docker-compose.yml new file mode 100644 index 000000000..5f1f961fa --- /dev/null +++ b/test-suite/fhevm/docker-compose/gateway-pause-docker-compose.yml @@ -0,0 +1,20 @@ +services: + gateway-sc-pause: + container_name: gateway-sc-pause + image: ghcr.io/zama-ai/fhevm/gateway-contracts:${GATEWAY_VERSION} + build: + context: ../../../gateway-contracts + dockerfile: Dockerfile + cache_from: + - type=gha + cache_to: + - type=gha,mode=max + env_file: + - ../env/staging/.env.gateway-sc.local + command: + - npx hardhat compile && npx hardhat task:pauseAllGatewayContracts + volumes: + - addresses-volume:/app/addresses # workdir in gateway's Dockerfile is /app + +volumes: + addresses-volume: diff --git a/test-suite/fhevm/docker-compose/gateway-unpause-docker-compose.yml b/test-suite/fhevm/docker-compose/gateway-unpause-docker-compose.yml new file mode 100644 index 000000000..667daca46 --- /dev/null +++ b/test-suite/fhevm/docker-compose/gateway-unpause-docker-compose.yml @@ -0,0 +1,20 @@ +services: + gateway-sc-unpause: + container_name: gateway-sc-unpause + image: ghcr.io/zama-ai/fhevm/gateway-contracts:${GATEWAY_VERSION} + build: + context: ../../../gateway-contracts + dockerfile: Dockerfile + cache_from: + - type=gha + cache_to: + - type=gha,mode=max + env_file: + - ../env/staging/.env.gateway-sc.local + command: + - npx hardhat compile && npx hardhat task:unpauseAllGatewayContracts + volumes: + - addresses-volume:/app/addresses # workdir in gateway's Dockerfile is /app + +volumes: + addresses-volume: diff --git a/test-suite/fhevm/env/staging/.env.gateway-sc b/test-suite/fhevm/env/staging/.env.gateway-sc index 2ea74348f..458e42e2f 100644 --- a/test-suite/fhevm/env/staging/.env.gateway-sc +++ b/test-suite/fhevm/env/staging/.env.gateway-sc @@ -98,6 +98,7 @@ NUM_PAUSERS="1" # Pauser 1 (accounts[7] - Gateway) PAUSER_ADDRESS_0="0x34B344B40eA9Ef21Da5653468a072780d19B1fa4" +PAUSER_PRIVATE_KEY="0x34aacca926bab195601bcf5702786d35cab968159b718ae671b226de11b9afee" # ============================================================================= # ProtocolPayment diff --git a/test-suite/fhevm/fhevm-cli b/test-suite/fhevm/fhevm-cli index 05e1cefeb..ff2bf5ba2 100755 --- a/test-suite/fhevm/fhevm-cli +++ b/test-suite/fhevm/fhevm-cli @@ -38,7 +38,7 @@ export HOST_VERSION=${HOST_VERSION:-"v0.10.0-2"} # Other services. export CORE_VERSION=${CORE_VERSION:-"v0.12.4"} export RELAYER_VERSION=${RELAYER_VERSION:-"v0.6.0"} -export TEST_SUITE_VERSION=${TEST_SUITE_VERSION:-"770f756"} +export TEST_SUITE_VERSION=${TEST_SUITE_VERSION:-"44b8c1f"} function print_logo() { @@ -58,6 +58,8 @@ function usage { echo echo -e "${BOLD}${LIGHT_BLUE}Commands:${RESET}" echo -e " ${YELLOW}deploy${RESET} ${CYAN}[--build]${RESET} WIP: Deploy the full fhevm stack (optionally rebuild images)" + echo -e " ${YELLOW}pause${RESET} ${CYAN}[CONTRACTS]${RESET} Pause specific contracts (host|gateway)" + echo -e " ${YELLOW}unpause${RESET} ${CYAN}[CONTRACTS]${RESET} Unpause specific contracts (host|gateway)" echo -e " ${YELLOW}test${RESET} ${CYAN}[TYPE]${RESET} Run tests (input-proof|user-decryption|public-decryption|erc20|debug)" echo -e " ${YELLOW}upgrade${RESET} ${CYAN}[SERVICE]${RESET} Upgrade specific service (host|gateway|connector|coprocessor|relayer|test-suite)" echo -e " ${YELLOW}clean${RESET} Remove all containers and volumes" @@ -108,6 +110,40 @@ case $COMMAND in echo -e "${GREEN}${BOLD} [SUCCESS] fhevm stack deployment complete!${RESET}" ;; + pause) + print_logo + CONTRACTS=$1 + if [[ ! $CONTRACTS =~ ^(gateway|host)$ ]]; then + echo -e "${RED}[ERROR]${RESET} ${BOLD}Unknown service: $CONTRACTS${RESET}" + usage + exit 1 + fi + + echo -e "${LIGHT_BLUE}[PAUSE]${RESET} ${BOLD}Pausing $CONTRACTS...${RESET}" + docker compose -p "${PROJECT}" -f "${SCRIPT_DIR}/docker-compose/${CONTRACTS}-pause-docker-compose.yml" up -d + # Wait for the pause service to complete + echo -e "${YELLOW}[WAIT]${RESET} ${BOLD}Waiting for pause operation to complete...${RESET}" + docker compose -p "${PROJECT}" -f "${SCRIPT_DIR}/docker-compose/${CONTRACTS}-pause-docker-compose.yml" wait ${CONTRACTS}-sc-pause + echo -e "${GREEN}[SUCCESS]${RESET} ${BOLD}$CONTRACTS paused successfully${RESET}" + ;; + + unpause) + print_logo + CONTRACTS=$1 + if [[ ! $CONTRACTS =~ ^(gateway|host)$ ]]; then + echo -e "${RED}[ERROR]${RESET} ${BOLD}Unknown service: $CONTRACTS${RESET}" + usage + exit 1 + fi + + echo -e "${LIGHT_BLUE}[UNPAUSE]${RESET} ${BOLD}Unpausing $CONTRACTS...${RESET}" + docker compose -p "${PROJECT}" -f "${SCRIPT_DIR}/docker-compose/${CONTRACTS}-unpause-docker-compose.yml" up -d + # Wait for the unpause service to complete + echo -e "${YELLOW}[WAIT]${RESET} ${BOLD}Waiting for unpause operation to complete...${RESET}" + docker compose -p "${PROJECT}" -f "${SCRIPT_DIR}/docker-compose/${CONTRACTS}-unpause-docker-compose.yml" wait ${CONTRACTS}-sc-unpause + echo -e "${GREEN}[SUCCESS]${RESET} ${BOLD}$CONTRACTS unpaused successfully${RESET}" + ;; + test) print_logo TEST_TYPE=$1 @@ -177,10 +213,18 @@ case $COMMAND in log_message="${LIGHT_BLUE}${BOLD}[TEST] INPUT PROOF (uint64)${RESET}" docker_args+=("-g" "test add 42 to uint64 input and decrypt") ;; + paused-gateway-input-proof) + log_message="${LIGHT_BLUE}${BOLD}[TEST] PAUSED INPUT PROOF (uint64)${RESET}" + docker_args+=("-g" "test paused gateway user input uint64") + ;; user-decryption) log_message="${LIGHT_BLUE}${BOLD}[TEST] USER DECRYPTION${RESET}" docker_args+=("-g" "test user decrypt") ;; + paused-gateway-user-decryption) + log_message="${LIGHT_BLUE}${BOLD}[TEST] PAUSED USER DECRYPTION${RESET}" + docker_args+=("-g" "test paused gateway user decrypt") + ;; erc20) log_message="${LIGHT_BLUE}${BOLD}[TEST] ERC20${RESET}" docker_args+=("-g" "should transfer tokens between two users.") @@ -193,6 +237,10 @@ case $COMMAND in log_message="${LIGHT_BLUE}${BOLD}[TEST] PUBLIC DECRYPTION OVER HTTP FOR MIXED${RESET}" docker_args+=("-g" "test HTTPPublicDecrypt mixed") ;; + paused-gateway-public-decrypt-http) + log_message="${LIGHT_BLUE}${BOLD}[TEST] PAUSED PUBLIC DECRYPTION OVER HTTP${RESET}" + docker_args+=("-g" "test paused gateway HTTPPublicDecrypt") + ;; operators) log_message="${LIGHT_BLUE}${BOLD}[TEST] OPERATORS${RESET}" docker_args+=("--parallel" "-g" "test operator|FHEVM manual operations")