diff --git a/.circleci/config.yml b/.circleci/config.yml index ff893fbe1d3..26822ffa1b1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,8 +3,7 @@ version: 2 reference: - workspace: &workspace - ~/src + workspace: &workspace ~/src ## Configurations android_config: &android_config working_directory: *workspace @@ -15,7 +14,6 @@ reference: TERM: dumb JVM_OPTS: -Xmx3200m - defaults: &defaults working_directory: ~/app docker: @@ -32,6 +30,11 @@ android-defaults: &android-defaults _JAVA_OPTIONS: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xmx1024m -XX:+HeapDumpOnOutOfMemoryError"' +e2e-defaults: &e2e-defaults + <<: *defaults + docker: + - image: celohq/circleci + general: artifacts: - "mobile/coverage" @@ -161,7 +164,7 @@ jobs: HOMEBREW_NO_AUTO_UPDATE=1 brew cask install android-platform-tools HOMEBREW_NO_AUTO_UPDATE=1 brew tap homebrew/cask-versions HOMEBREW_NO_AUTO_UPDATE=1 brew cask install homebrew/cask-versions/adoptopenjdk8 - - run: + - run: name: Creace Android Virtual Device (AVD) command: | avdmanager create avd -n Nexus_5X_API_28_x86 -k "system-images;android-26;google_apis;x86" -g google_apis -d "Nexus 5" @@ -182,7 +185,7 @@ jobs: name: install miscellaneous command: HOMEBREW_NO_AUTO_UPDATE=1 brew install tree # Currently not used - # - run: npm install --global react-native-kill-packager + # - run: npm install --global react-native-kill-packager - run: # need to run this because it's another OS than install_dependecies job name: yarn @@ -196,7 +199,7 @@ jobs: # yarn postinstall # fi yarn - yarn build + yarn build - save_cache: key: yarn-v4-macos-{{ .Branch }}-{{ checksum "yarn.lock" }} paths: @@ -212,7 +215,7 @@ jobs: name: Start emulator command: cd ~/src/packages/mobile && bash ./scripts/start_emulator.sh background: true - - run: + - run: name: Start metro command: cd ~/src/packages/mobile && yarn start background: true @@ -237,7 +240,7 @@ jobs: paths: - ~/src/packages/mobile/android/app/build/outputs/apk/ - ~/.gradle/ - + lint-checks: <<: *defaults steps: @@ -460,7 +463,7 @@ jobs: steps: - attach_workspace: at: ~/app - + - run: name: Install and test the npm package command: | @@ -475,7 +478,7 @@ jobs: steps: - attach_workspace: at: ~/app - + - run: name: Install and test the npm package command: | @@ -486,7 +489,7 @@ jobs: npm install ~/app/packages/utils/*.tgz end-to-end-geth-transfer-test: - <<: *defaults + <<: *e2e-defaults steps: - attach_workspace: at: ~/app @@ -495,37 +498,16 @@ jobs: command: | FILES_TO_CHECK="${PWD}/packages/celotool,${PWD}/packages/protocol,${PWD}/.circleci/config.yml" ./scripts/ci_check_if_test_should_run_v2.sh ${FILES_TO_CHECK} - - run: - name: Setup Go language - command: | - set -e - set -v - wget https://dl.google.com/go/go1.11.5.linux-amd64.tar.gz - tar xf go1.11.5.linux-amd64.tar.gz -C /tmp - ls /tmp/go/bin/go - /tmp/go/bin/go version - - run: - name: Setup Rust language - command: | - set -e - set -v - curl https://sh.rustup.rs -sSf | sh -s -- -y - export PATH=${PATH}:~/.cargo/bin:/tmp/go/bin - rustup install 1.36.0 - rustup default 1.36.0 - run: name: Run test no_output_timeout: 20m command: | set -e - export PATH=${PATH}:~/.cargo/bin:/tmp/go/bin - go version cd packages/celotool - mkdir ~/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config ./ci_test_transfers.sh checkout master end-to-end-geth-exit-test: - <<: *defaults + <<: *e2e-defaults steps: - attach_workspace: at: ~/app @@ -534,37 +516,16 @@ jobs: command: | FILES_TO_CHECK="${PWD}/packages/celotool,${PWD}/packages/protocol,${PWD}/.circleci/config.yml" ./scripts/ci_check_if_test_should_run_v2.sh ${FILES_TO_CHECK} - - run: - name: Setup Go language - command: | - set -e - set -v - wget https://dl.google.com/go/go1.11.5.linux-amd64.tar.gz - tar xf go1.11.5.linux-amd64.tar.gz -C /tmp - ls /tmp/go/bin/go - /tmp/go/bin/go version - - run: - name: Setup Rust language - command: | - set -e - set -v - curl https://sh.rustup.rs -sSf | sh -s -- -y - export PATH=${PATH}:~/.cargo/bin:/tmp/go/bin - rustup install 1.36.0 - rustup default 1.36.0 - run: name: Run test no_output_timeout: 20m command: | set -e - export PATH=${PATH}:~/.cargo/bin:/tmp/go/bin - go version cd packages/celotool - mkdir ~/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config ./ci_test_exit.sh checkout master end-to-end-geth-governance-test: - <<: *defaults + <<: *e2e-defaults # Source: https://circleci.com/docs/2.0/configuration-reference/#resource_class resource_class: medium+ steps: @@ -575,37 +536,16 @@ jobs: command: | FILES_TO_CHECK="${PWD}/packages/celotool,${PWD}/packages/protocol,${PWD}/.circleci/config.yml" ./scripts/ci_check_if_test_should_run_v2.sh ${FILES_TO_CHECK} - - run: - name: Setup Go language - command: | - set -e - set -v - wget https://dl.google.com/go/go1.11.5.linux-amd64.tar.gz - tar xf go1.11.5.linux-amd64.tar.gz -C /tmp - ls /tmp/go/bin/go - /tmp/go/bin/go version - - run: - name: Setup Rust language - command: | - set -e - set -v - curl https://sh.rustup.rs -sSf | sh -s -- -y - export PATH=${PATH}:~/.cargo/bin:/tmp/go/bin - rustup install 1.36.0 - rustup default 1.36.0 - run: name: Run test no_output_timeout: 20m command: | set -e - export PATH=${PATH}:~/.cargo/bin:/tmp/go/bin - go version cd packages/celotool - mkdir ~/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config ./ci_test_governance.sh checkout master end-to-end-geth-sync-test: - <<: *defaults + <<: *e2e-defaults # Source: https://circleci.com/docs/2.0/configuration-reference/#resource_class resource_class: medium+ steps: @@ -616,36 +556,15 @@ jobs: command: | FILES_TO_CHECK="${PWD}/packages/celotool,${PWD}/packages/protocol,${PWD}/.circleci/config.yml" ./scripts/ci_check_if_test_should_run_v2.sh ${FILES_TO_CHECK} - - run: - name: Setup Go language - command: | - set -e - set -v - wget https://dl.google.com/go/go1.11.5.linux-amd64.tar.gz - tar xf go1.11.5.linux-amd64.tar.gz -C /tmp - ls /tmp/go/bin/go - /tmp/go/bin/go version - - run: - name: Setup Rust language - command: | - set -e - set -v - curl https://sh.rustup.rs -sSf | sh -s -- -y - export PATH=${PATH}:~/.cargo/bin:/tmp/go/bin - rustup install 1.36.0 - rustup default 1.36.0 - run: name: Run test command: | set -e - export PATH=${PATH}:~/.cargo/bin:/tmp/go/bin - go version cd packages/celotool - mkdir ~/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config ./ci_test_sync.sh checkout master end-to-end-geth-integration-sync-test: - <<: *defaults + <<: *e2e-defaults steps: - attach_workspace: at: ~/app @@ -655,27 +574,29 @@ jobs: FILES_TO_CHECK="${PWD}/packages/celotool,${PWD}/packages/protocol,${PWD}/.circleci/config.yml" ./scripts/ci_check_if_test_should_run_v2.sh ${FILES_TO_CHECK} - run: - name: Setup Go language + name: Run test command: | set -e - set -v - wget https://dl.google.com/go/go1.11.5.linux-amd64.tar.gz - tar xf go1.11.5.linux-amd64.tar.gz -C /tmp - ls /tmp/go/bin/go - /tmp/go/bin/go version - curl https://sh.rustup.rs -sSf | sh -s -- -y - export PATH=${PATH}:~/.cargo/bin:/tmp/go/bin - rustup install 1.36.0 - rustup default 1.36.0 + cd packages/celotool + ./ci_test_sync_with_network.sh checkout master + + end-to-end-geth-attestations-test: + <<: *e2e-defaults + resource_class: medium+ + steps: + - attach_workspace: + at: ~/app + - run: + name: Check if the test should run + command: | + FILES_TO_CHECK="${PWD}/packages/celotool,${PWD}/packages/protocol,${PWD}/.circleci/config.yml" + ./scripts/ci_check_if_test_should_run_v2.sh ${FILES_TO_CHECK} - run: name: Run test command: | set -e - export PATH=${PATH}:~/.cargo/bin:/tmp/go/bin - go version cd packages/celotool - mkdir ~/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config - ./ci_test_sync_with_network.sh checkout master + ./ci_test_attestations.sh checkout master web: working_directory: ~/app @@ -788,23 +709,27 @@ workflows: - end-to-end-geth-transfer-test: requires: - lint-checks - - walletkit-test + - contractkit-test - end-to-end-geth-exit-test: requires: - lint-checks - - walletkit-test + - contractkit-test - end-to-end-geth-governance-test: requires: - lint-checks - - walletkit-test + - contractkit-test - end-to-end-geth-sync-test: requires: - lint-checks - - walletkit-test + - contractkit-test - end-to-end-geth-integration-sync-test: requires: - lint-checks - - walletkit-test + - contractkit-test + - end-to-end-geth-attestations-test: + requires: + - lint-checks + - contractkit-test npm-install-testing-cron-workflow: triggers: - schedule: diff --git a/dockerfiles/circleci/Dockerfile b/dockerfiles/circleci/Dockerfile index a42dd0b3ab3..cbe05cb1ebc 100644 --- a/dockerfiles/circleci/Dockerfile +++ b/dockerfiles/circleci/Dockerfile @@ -16,4 +16,18 @@ RUN export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \ curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - && \ sudo apt-get update -y && sudo apt-get install google-cloud-sdk -y +RUN sudo wget https://dl.google.com/go/go1.11.5.linux-amd64.tar.gz && \ + sudo tar xf go1.11.5.linux-amd64.tar.gz -C /usr/local + +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y + +ENV PATH="/usr/local/go/bin:/home/circleci/.cargo/bin:${PATH}" + +RUN go version + +RUN rustup install 1.36.0 && \ + rustup default 1.36.0 + +RUN mkdir ~/.ssh/ && echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config + CMD ["/bin/sh"] diff --git a/packages/celotool/ci_test_attestations.sh b/packages/celotool/ci_test_attestations.sh new file mode 100755 index 00000000000..493ce855996 --- /dev/null +++ b/packages/celotool/ci_test_attestations.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +# This test starts a standalone Geth node and runs transactions on it. + +# For testing a particular branch of Geth repo (usually, on Circle CI) +# Usage: ci_test_attestations.sh checkout +# For testing the local Geth dir (usually, for manual testing) +# Usage: ci_test_attestations.sh local + +if [ "${1}" == "checkout" ]; then + # Test master by default. + BRANCH_TO_TEST=${2:-"master"} + echo "Checking out geth at branch ${BRANCH_TO_TEST}..." + ../../node_modules/.bin/mocha -r ts-node/register src/e2e-tests/attestations_tests.ts --branch ${BRANCH_TO_TEST} +elif [ "${1}" == "local" ]; then + export GETH_DIR="${2}" + echo "Testing using local geth dir ${GETH_DIR}..." + ../../node_modules/.bin/mocha -r ts-node/register src/e2e-tests/attestations_tests.ts --localgeth ${GETH_DIR} +fi diff --git a/packages/celotool/src/cmds/account/verify.ts b/packages/celotool/src/cmds/account/verify.ts index 89b044d89c4..63b16bc48d4 100644 --- a/packages/celotool/src/cmds/account/verify.ts +++ b/packages/celotool/src/cmds/account/verify.ts @@ -1,6 +1,6 @@ import { AccountArgv } from '@celo/celotool/src/cmds/account' import { portForwardAnd } from '@celo/celotool/src/lib/port_forward' -import { CeloContract, newKit } from '@celo/contractkit' +import { newKit } from '@celo/contractkit' import { AttestationsWrapper } from '@celo/contractkit/lib/wrappers/Attestations' import { ActionableAttestation, decodeAttestationCode } from '@celo/walletkit' import prompts from 'prompts' @@ -100,10 +100,10 @@ async function requestMoreAttestations( attestationsRequested: number ) { await attestations - .approveAttestationFee(CeloContract.StableToken, attestationsRequested) + .approveAttestationFee(attestationsRequested) .then((txo) => txo.sendAndWaitForReceipt()) await attestations - .request(phoneNumber, attestationsRequested, CeloContract.StableToken) + .request(phoneNumber, attestationsRequested) .then((txo) => txo.sendAndWaitForReceipt()) } diff --git a/packages/celotool/src/e2e-tests/attestations_tests.ts b/packages/celotool/src/e2e-tests/attestations_tests.ts new file mode 100644 index 00000000000..f9bcf5f07d9 --- /dev/null +++ b/packages/celotool/src/e2e-tests/attestations_tests.ts @@ -0,0 +1,63 @@ +import { ContractKit, newKit } from '@celo/contractkit' +import { AttestationsWrapper } from '@celo/contractkit/lib/wrappers/Attestations' +import { assert } from 'chai' +import { getContext, GethTestConfig, sleep } from './utils' + +const validatorAddress = '0x47e172f6cfb6c7d01c1574fa3e2be7cc73269d95' +const phoneNumber = '+15555555555' + +describe('governance tests', () => { + const gethConfig: GethTestConfig = { + migrate: true, + instances: [ + { name: 'validator0', validating: true, syncmode: 'full', port: 30303, rpcport: 8545 }, + { name: 'validator1', validating: true, syncmode: 'full', port: 30305, rpcport: 8547 }, + { name: 'validator2', validating: true, syncmode: 'full', port: 30307, rpcport: 8549 }, + { name: 'validator3', validating: true, syncmode: 'full', port: 30309, rpcport: 8551 }, + { name: 'validator4', validating: true, syncmode: 'full', port: 30311, rpcport: 8553 }, + ], + } + + const context: any = getContext(gethConfig) + let contractKit: ContractKit + let Attestations: AttestationsWrapper + + before(async function(this: any) { + this.timeout(0) + await context.hooks.before() + }) + + after(context.hooks.after) + + const restart = async () => { + await context.hooks.restart() + contractKit = newKit('http://localhost:8545') + contractKit.defaultAccount = validatorAddress + + // TODO(mcortesi): magic sleep. without it unlockAccount sometimes fails + await sleep(2) + // Assuming empty password + await contractKit.web3.eth.personal.unlockAccount(validatorAddress, '', 1000000) + Attestations = await contractKit.contracts.getAttestations() + } + + describe('Attestations', () => { + before(async function() { + this.timeout(0) + await restart() + }) + + it('requests an attestation', async function(this: any) { + this.timeout(10000) + const approve = await Attestations.approveAttestationFee(2) + await approve.sendAndWaitForReceipt() + const request = await Attestations.request(phoneNumber, 2) + await request.sendAndWaitForReceipt() + + const stats = await Attestations.getAttestationStat(phoneNumber, validatorAddress) + assert.equal(stats.total, 2) + const actionable = await Attestations.getActionableAttestations(phoneNumber, validatorAddress) + assert.lengthOf(actionable, 2) + }) + }) +}) diff --git a/packages/celotool/src/e2e-tests/exit_test.ts b/packages/celotool/src/e2e-tests/exit_test.ts index 36be7785665..b0f06387942 100644 --- a/packages/celotool/src/e2e-tests/exit_test.ts +++ b/packages/celotool/src/e2e-tests/exit_test.ts @@ -1,5 +1,5 @@ import Web3 from 'web3' -import { getContractAddress, getHooks, sleep } from './utils' +import { getContractAddress, getHooks, GethTestConfig, sleep } from './utils' const blockchainParametersAbi = [ { @@ -29,9 +29,8 @@ const blockchainParametersAbi = [ describe('exit tests', function(this: any) { this.timeout(0) - const gethConfig = { + const gethConfig: GethTestConfig = { migrateTo: 15, - migrateGovernance: false, instances: [ { name: 'validator', validating: true, syncmode: 'full', port: 30303, rpcport: 8545 }, ], diff --git a/packages/celotool/src/e2e-tests/transfer_tests.ts b/packages/celotool/src/e2e-tests/transfer_tests.ts index 3d22ddef327..0c24c64a303 100644 --- a/packages/celotool/src/e2e-tests/transfer_tests.ts +++ b/packages/celotool/src/e2e-tests/transfer_tests.ts @@ -12,6 +12,7 @@ import { getEnode, GethInstanceConfig, getHooks, + GethTestConfig, initAndStartGeth, killInstance, sleep, @@ -170,9 +171,8 @@ describe('Transfer tests', function(this: any) { const FeeRecipientAddress = '0x4f5f8a3f45d179553e7b95119ce296010f50f6f1' const syncModes = ['full', 'fast', 'light', 'ultralight'] - const gethConfig = { + const gethConfig: GethTestConfig = { migrateTo: 8, - migrateGovernance: false, instances: [ { name: 'validator', validating: true, syncmode: 'full', port: 30303, rpcport: 8545 }, ], diff --git a/packages/contractkit/src/wrappers/Attestations.ts b/packages/contractkit/src/wrappers/Attestations.ts index 270b53bf5ce..dc78173ebb5 100644 --- a/packages/contractkit/src/wrappers/Attestations.ts +++ b/packages/contractkit/src/wrappers/Attestations.ts @@ -2,7 +2,7 @@ import { ECIES, PhoneNumberUtils, SignatureUtils } from '@celo/utils' import { zip3 } from '@celo/utils/lib/collections' import BigNumber from 'bignumber.js' import * as Web3Utils from 'web3-utils' -import { Address, CeloToken } from '../base' +import { Address, CeloContract } from '../base' import { Attestations } from '../generated/types/Attestations' import { BaseWrapper, @@ -128,25 +128,23 @@ export class AttestationsWrapper extends BaseWrapper { setWalletAddress = proxySend(this.kit, this.contract.methods.setWalletAddress) /** - * Calculates the amount of CeloToken to request Attestations - * @param token The token to pay for attestations for - * @param attestationsRequested The number of attestations to request + * Calculates the amount of StableToken required to request Attestations + * @param attestationsRequested The number of attestations to request */ - async approveAttestationFee(token: CeloToken, attestationsRequested: number) { - const tokenContract = await this.kit.contracts.getContract(token) - const fee = await this.attestationFeeRequired(token, attestationsRequested) - return tokenContract.approve(this.address, fee.toString()) + async attestationFeeRequired(attestationsRequested: number) { + const tokenAddress = await this.kit.registry.addressFor(CeloContract.StableToken) + const attestationFee = await this.contract.methods.getAttestationRequestFee(tokenAddress).call() + return new BigNumber(attestationFee).times(attestationsRequested) } /** - * Approves the transfer of CeloToken to request Attestations - * @param token The token to pay for attestations for - * @param attestationsRequested The number of attestations to request + * Approves the necessary amount of StableToken to request Attestations + * @param attestationsRequested The number of attestations to request */ - async attestationFeeRequired(token: CeloToken, attestationsRequested: number) { - const tokenAddress = await this.kit.registry.addressFor(token) - const attestationFee = await this.contract.methods.getAttestationRequestFee(tokenAddress).call() - return new BigNumber(attestationFee).times(attestationsRequested) + async approveAttestationFee(attestationsRequested: number) { + const tokenContract = await this.kit.contracts.getContract(CeloContract.StableToken) + const fee = await this.attestationFeeRequired(attestationsRequested) + return tokenContract.approve(this.address, fee.toString()) } /** @@ -300,11 +298,10 @@ export class AttestationsWrapper extends BaseWrapper { * Requests attestations for a phone number * @param phoneNumber The phone number for which to request attestations for * @param attestationsRequested The number of attestations to request - * @param token The token with which to pay for the attestation fee */ - async request(phoneNumber: string, attestationsRequested: number, token: CeloToken) { + async request(phoneNumber: string, attestationsRequested: number) { const phoneHash = PhoneNumberUtils.getPhoneHash(phoneNumber) - const tokenAddress = await this.kit.registry.addressFor(token) + const tokenAddress = await this.kit.registry.addressFor(CeloContract.StableToken) return toTransactionObject( this.kit, this.contract.methods.request(phoneHash, attestationsRequested, tokenAddress)