├── .drone.yml ├── .env-template ├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── contracts ├── Enigma.sol ├── EnigmaSimulation.sol ├── EnigmaToken.sol ├── Migrations.sol ├── Sample.sol ├── VotingETH.sol ├── impl │ ├── EnigmaCommon.sol │ ├── EnigmaEvents.sol │ ├── EnigmaState.sol │ ├── EnigmaStorage.sol │ ├── Getters.sol │ ├── PrincipalImpl.sol │ ├── PrincipalImplSimulation.sol │ ├── SecretContractImpl.sol │ ├── TaskImpl.sol │ ├── TaskImplSimulation.sol │ ├── WorkersImpl.sol │ └── WorkersImplSimulation.sol ├── interfaces │ ├── ERC20.sol │ └── IEnigma.sol └── utils │ ├── Base64.sol │ ├── Bytes.sol │ ├── GetCode2.sol │ ├── Memory.sol │ └── SolRsaVerify.sol ├── deploy-ganache.sh ├── enigma-js ├── .babelrc ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .npmignore ├── .nvmrc ├── README.md ├── jest.init.js ├── lib │ ├── enigma-js.js │ ├── enigma-js.js.map │ ├── enigma-js.min.js │ ├── enigma-js.min.js.map │ ├── enigma-js.node.js │ ├── enigma-js.node.js.map │ ├── enigma-js.node.min.js │ └── enigma-js.node.min.js.map ├── package.json ├── src │ ├── Admin.js │ ├── Enigma.js │ ├── Server.js │ ├── emitterConstants.js │ ├── enigma-utils.js │ ├── index.js │ └── models │ │ └── Task.js ├── test │ ├── Enigma.spec.js │ ├── data.js │ ├── enigma-utils.spec.js │ ├── integrationTests │ │ ├── README.md │ │ ├── contractLoader.js │ │ ├── jest.config.js │ │ ├── runTests.bash │ │ ├── secretContracts │ │ │ ├── calculator.wasm │ │ │ ├── erc20.wasm │ │ │ ├── flipcoin.wasm │ │ │ ├── millionaire.wasm │ │ │ └── voting.wasm │ │ ├── template.01_init.js │ │ ├── template.02_deploy_calculator.js │ │ ├── template.02_deploy_erc20.js │ │ ├── template.02_deploy_flipcoin.js │ │ ├── template.02_deploy_millionaire.js │ │ ├── template.02_deploy_voting.js │ │ ├── template.03_deploy_fail_bytecode.js │ │ ├── template.03_deploy_fail_constructor.js │ │ ├── template.03_deploy_fail_outofgas.js │ │ ├── template.03_deploy_fail_parameters.js │ │ ├── template.03_deploy_fail_wrong_encryption_key.js │ │ ├── template.03_deploy_fail_wrong_eth_address.js │ │ ├── template.03_deploy_fail_wrongworker.js │ │ ├── template.10_execute_calculator.js │ │ ├── template.10_execute_erc20.js │ │ ├── template.10_execute_flipcoin.js │ │ ├── template.10_execute_millionaire.js │ │ ├── template.10_execute_voting.js │ │ ├── template.20_execute_fail_nonexistent.js │ │ ├── template.20_execute_fail_outofgas.js │ │ ├── template.20_execute_fail_parameters.js │ │ ├── template.20_execute_fail_wrong_encryption_key.js │ │ ├── template.20_execute_fail_wrong_eth_address.js │ │ ├── template.20_execute_fail_wrong_eth_payload.js │ │ ├── template.20_execute_fail_wrongworker.js │ │ ├── template.90_advance_epoch.js │ │ ├── template.99_cleanup.js │ │ ├── testConstants.js │ │ └── testList.template.txt │ ├── mocha.opts │ └── principal-utils.js ├── webpack.config.js └── yarn.lock ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── package.json ├── scripts ├── checkSimulationContracts.bash ├── copy-contracts-to-enigma-core.sh └── deploy.sh ├── simulate-coin-mixer.sh ├── truffle.js ├── utils ├── generate-principal-msg-hash.js ├── get-active-workers.js ├── parse-enigma-abi.js ├── print-receipt.js └── register-compare-reports.js └── yarn.lock /.drone.yml: -------------------------------------------------------------------------------- 1 | kind: pipeline 2 | name: default 3 | steps: 4 | 5 | - name: integration 6 | image: enigmampc/docker-client 7 | privileged: true 8 | volumes: 9 | - name: sock 10 | path: /var/run/docker.sock 11 | commands: 12 | - git clone https://github.com/enigmampc/discovery-docker-network.git 13 | - cd discovery-docker-network && cp .env-template .env 14 | - sed -i "s/COMPOSE_PROJECT_NAME=.*/COMPOSE_PROJECT_NAME=enigma_${DRONE_BUILD_NUMBER}/" .env 15 | - export MATCHING_BRANCH_CORE="$(git ls-remote --heads https://github.com/enigmampc/enigma-core.git ${DRONE_BRANCH} | wc -l)" 16 | - export MATCHING_BRANCH_P2P="$(git ls-remote --heads https://github.com/enigmampc/enigma-p2p.git ${DRONE_BRANCH} | wc -l)" 17 | - export DOCKER_TAG=p2p_${DRONE_BUILD_NUMBER} 18 | - sed -i "s/DOCKER_TAG=latest/DOCKER_TAG=${DOCKER_TAG}/" .env; 19 | - | 20 | /bin/bash -c ' 21 | declare -a PROJECTS=(core km p2p) 22 | declare -A DOCKER_IMAGES=([core]=enigma_core_hw [km]=enigma_km_hw [p2p]=enigma_p2p) 23 | declare -A GIT_BRANCH_ARG=([core]=GIT_BRANCH_CORE [km]=GIT_BRANCH_CORE [p2p]=GIT_BRANCH_P2P) 24 | declare -A PROJECT_DIRECTORY=([core]=enigma-core [km]=enigma-core [p2p]=enigma-p2p) 25 | declare -A PROJECT_BRANCH_FOUND=([core]=$MATCHING_BRANCH_CORE [km]=$MATCHING_BRANCH_CORE [p2p]=$MATCHING_BRANCH_P2P) 26 | for project in $${PROJECTS[@]}; do 27 | DOCKER_IMAGE="enigmampc/$${DOCKER_IMAGES[$project]}" 28 | if [[ "$DRONE_BRANCH" == "master" ]]; then 29 | docker pull "$DOCKER_IMAGE:latest" 30 | docker tag "$DOCKER_IMAGE:latest" "$DOCKER_IMAGE:$DOCKER_TAG" 31 | elif [ "$${PROJECT_BRANCH_FOUND[$project]}" -eq 0 ]; then 32 | docker pull "$DOCKER_IMAGE:develop" 33 | docker tag "$DOCKER_IMAGE:develop" "$DOCKER_IMAGE:$DOCKER_TAG" 34 | else 35 | cd "$${PROJECT_DIRECTORY[$project]}" 36 | if [[ "$project" == "km" ]]; then 37 | docker build -f Dockerfile.km --build-arg GIT_BRANCH_CORE=${DRONE_BRANCH} --build-arg SGX_MODE=HW -t "$DOCKER_IMAGE:$DOCKER_TAG" --no-cache . 38 | elif [[ "$project" == "core" ]]; then 39 | docker build --build-arg GIT_BRANCH_CORE=${DRONE_BRANCH} --build-arg SGX_MODE=HW -t "$DOCKER_IMAGE:$DOCKER_TAG" --no-cache . 40 | else 41 | docker build --build-arg "$${GIT_BRANCH_ARG[$project]}=${DRONE_BRANCH}" -t "$DOCKER_IMAGE:$DOCKER_TAG" --no-cache . 42 | fi 43 | cd .. 44 | fi 45 | done' 46 | - cd enigma-contract && docker build --build-arg GIT_BRANCH_CONTRACT=${DRONE_BRANCH} -t enigmampc/enigma_contract:$DOCKER_TAG --no-cache . && cd .. 47 | - export NODES=3 48 | - docker-compose -f docker-compose.yml -f docker-compose.hw.yml -f docker-compose.test.yml up --scale core=$NODES --scale p2p=$NODES --exit-code-from client && export RESULT=$? || export RESULT=$? 49 | - docker-compose -f docker-compose.yml -f docker-compose.hw.yml down -v --rmi all || true 50 | - if [ $RESULT -ne 0 ]; then exit 1; fi 51 | 52 | - name: deploy 53 | image: enigmampc/docker-client 54 | depends_on: 55 | - integration 56 | when: 57 | branch: 58 | - develop 59 | - master 60 | privileged: true 61 | volumes: 62 | - name: sock 63 | path: /var/run/docker.sock 64 | environment: 65 | USERNAME: 66 | from_secret: username 67 | PASSWORD: 68 | from_secret: password 69 | commands: 70 | - cd discovery-docker-network/enigma-contract 71 | - echo $PASSWORD | docker login -u $USERNAME --password-stdin 72 | - if [[ ${DRONE_BRANCH} == "master" ]]; then export DOCKER_TAG=latest; else export DOCKER_TAG=develop; fi 73 | - docker build --build-arg GIT_BRANCH_CONTRACT=${DRONE_BRANCH} -t enigmampc/enigma_contract:$DOCKER_TAG --no-cache . 74 | - docker push enigmampc/enigma_contract:$DOCKER_TAG 75 | 76 | volumes: 77 | - name: sock 78 | host: 79 | path: /var/run/docker.sock 80 | -------------------------------------------------------------------------------- /.env-template: -------------------------------------------------------------------------------- 1 | SGX_MODE=SW -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/contracts/Migrations.json 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | *.pid.lock 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # nyc test coverage 22 | .nyc_output 23 | 24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # Bower dependency directory (https://bower.io/) 28 | bower_components 29 | 30 | # node-waf configuration 31 | .lock-wscript 32 | 33 | # Compiled binary addons (https://nodejs.org/api/addons.html) 34 | build/Release 35 | 36 | # Dependency directories 37 | node_modules/ 38 | jspm_packages/ 39 | 40 | # TypeScript v1 declaration files 41 | typings/ 42 | 43 | # Optional npm cache directory 44 | .npm 45 | 46 | # Optional eslint cache 47 | .eslintcache 48 | 49 | # Optional REPL history 50 | .node_repl_history 51 | 52 | # Output of 'npm pack' 53 | *.tgz 54 | 55 | # Yarn Integrity file 56 | .yarn-integrity 57 | 58 | # dotenv environment variables file 59 | .env 60 | 61 | # next.js build output 62 | .next 63 | 64 | # Codecov 65 | coverage.lcov 66 | 67 | # IDE 68 | .idea/ 69 | 70 | .DS_Store 71 | 72 | build 73 | enigmacontract.txt 74 | enigmatokencontract.txt 75 | 76 | # integrationTests 77 | enigma-js/test/integrationTests/*.spec.js 78 | enigma-js/test/integrationTests/testList.txt 79 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | sudo: true 4 | 5 | node_js: 6 | - "10.16" 7 | 8 | install: 9 | - ./scripts/checkSimulationContracts.bash 10 | - yarn install 11 | - yarn global add ganache-cli truffle 12 | - pushd enigma-js && yarn install && popd 13 | 14 | before_script: 15 | - ganache-cli -p 9545 -i 4447 & 16 | - sleep 5 17 | 18 | script: 19 | - set -e 20 | - rm -rf build 21 | - truffle compile 22 | - truffle migrate --reset --network develop 23 | - pushd enigma-js && yarn build && popd 24 | - SGX_MODE=SW truffle migrate --reset --network develop 25 | - pushd enigma-js && SGX_MODE=SW yarn test && popd 26 | 27 | after_success: 28 | - pushd enigma-js && yarn report-coverage && popd 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # enigma-contract 2 | 3 | | Branch | Build | Code Coverage | 4 | |--------|-------|---------------| 5 | | Master | [![Build Status](https://travis-ci.org/enigmampc/enigma-contract.svg?branch=master)](https://travis-ci.org/enigmampc/enigma-contract) | [![codecov](https://codecov.io/gh/enigmampc/enigma-contract/branch/master/graph/badge.svg?token=mhsubU24ud)](https://codecov.io/gh/enigmampc/enigma-contract) | 6 | | Develop | [![Build Status](https://travis-ci.org/enigmampc/enigma-contract.svg?branch=develop)](https://travis-ci.org/enigmampc/enigma-contract) | [![codecov](https://codecov.io/gh/enigmampc/enigma-contract/branch/develop/graph/badge.svg?token=mhsubU24ud)](https://codecov.io/gh/enigmampc/enigma-contract) | 7 | 8 | The Solidity contracts and the [Javascript client library](enigma-js/) of the Enigma Network with a Truffle test bed. 9 | 10 | For more information, refer to the [Protocol documentation](https://enigma.co/protocol) for more information, as well as the [client library README](enigma-js/README.md). 11 | 12 | ## Configuration 13 | 14 | The Enigma contract supports both Hardware and Software (aka Simulation) SGX modes for the enclaves running on the Engima network. The distinction comes when the enclaves register with the contract, when they must include a Remote Attestation report signed by Intel that verifies the enclaves credentials. In the case of Simulation mode that report is empty, and the contract skips the mandatory signature verifications enforced in Hardware mode. 15 | 16 | Simulation mode is only supported for development purposes in environments without access to hosts with SGX capabilities. For security reasons, there are two different sets of contracts for Hardware and Software mode (instead of having a switch or conditional block inside the contract that will end on mainnet). The selection between either mode is conditional at the time of doing the contract migrations based on the environment variable `SGX_MODE`. Only when it is set to `SW`, the simulation mode will be enabled. In all other cases, it will run in Hardware mode. 17 | 18 | For reference, an `.env-template` is provided that can be copied over to `.env` to manage the setting of this environment variable. 19 | 20 | ## License 21 | 22 | The Enigma Contract is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by 23 | the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 24 | 25 | This program 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 Affero General Public License for more details. 26 | 27 | You should have received a [copy](LICENSE) of the GNU Affero General Public License along with this program. If not, see . 28 | -------------------------------------------------------------------------------- /contracts/EnigmaToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 3 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol"; 4 | 5 | /** 6 | * @title Enigma Token 7 | * @dev ERC20 Enigma Token (ENG) 8 | * 9 | * ENG Tokens are divisible by 1e8 (100,000,000) base 10 | * units referred to as 'Grains'. 11 | * 12 | * ENG are displayed using 8 decimal places of precision. 13 | * 14 | * 1 ENG is equivalent to: 15 | * 100000000 == 1 * 10**8 == 1e8 == One Hundred Million Grains 16 | * 17 | * 150 million ENG (total supply) is equivalent to: 18 | * 15000000000000000 == 150000000 * 10**8 == 1e17 19 | * 20 | * All initial ENG Grains are assigned to the creator of 21 | * this contract. 22 | * 23 | */ 24 | contract EnigmaToken is ERC20, ERC20Detailed { 25 | 26 | uint256 public constant INITIAL_SUPPLY = 150000000 * 10**8; // 150 million ENG specified in Grains 27 | 28 | /** 29 | * @dev EnigmaToken Constructor 30 | * Runs only on initial contract creation. 31 | */ 32 | constructor() public ERC20Detailed("Enigma", "ENG", 8) { 33 | _mint(msg.sender, INITIAL_SUPPLY); 34 | } 35 | 36 | /** 37 | * @dev Transfer token for a specified address when not paused 38 | * @param _to The address to transfer to. 39 | * @param _value The amount to be transferred. 40 | */ 41 | function transfer(address _to, uint256 _value) public returns (bool) { 42 | return super.transfer(_to, _value); 43 | } 44 | 45 | /** 46 | * @dev Transfer tokens from one address to another when not paused 47 | * @param _from address The address which you want to send tokens from 48 | * @param _to address The address which you want to transfer to 49 | * @param _value uint256 the amount of tokens to be transferred 50 | */ 51 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { 52 | return super.transferFrom(_from, _to, _value); 53 | } 54 | 55 | /** 56 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender when not paused. 57 | * @param _spender The address which will spend the funds. 58 | * @param _value The amount of tokens to be spent. 59 | */ 60 | function approve(address _spender, uint256 _value) public returns (bool) { 61 | return super.approve(_spender, _value); 62 | } 63 | 64 | function allowance(address _owner, address _spender) public view returns (uint256) { 65 | return super.allowance(_owner,_spender); 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | modifier restricted() { 8 | if (msg.sender == owner) { 9 | _; 10 | } 11 | } 12 | 13 | constructor() public { 14 | owner = msg.sender; 15 | } 16 | 17 | function setCompleted(uint completed) public restricted { 18 | last_completed_migration = completed; 19 | } 20 | 21 | function upgrade(address new_address) public restricted { 22 | Migrations upgraded = Migrations(new_address); 23 | upgraded.setCompleted(last_completed_migration); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /contracts/Sample.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | contract Sample { 5 | uint public stateInt; 6 | bool public stateBool; 7 | uint public counter; 8 | 9 | constructor() public { 10 | stateInt = 1; 11 | stateBool = false; 12 | } 13 | 14 | function setStateVar(uint _stateInt, bool _stateBool) public { 15 | stateInt = _stateInt; 16 | stateBool = _stateBool; 17 | } 18 | 19 | // Used in unit tests to simulate graceful deploy and compute receipt handling of callbacks that fail due to 20 | // out of gas errors. This function contains a very large loop, that eventually fails due to out of gas. 21 | function setStateVarGasFail(uint _stateInt, bool _stateBool) public { 22 | stateInt = _stateInt; 23 | stateBool = _stateBool; 24 | for (uint i = 0; i < 1000000; i++) { 25 | stateInt = i; 26 | stateBool = (i % 2 == 0); 27 | } 28 | } 29 | 30 | function setStateVarRevert(uint _stateInt, bool _stateBool) public { 31 | stateInt = _stateInt; 32 | stateBool = _stateBool; 33 | require(false, "Failed in eth call"); 34 | } 35 | 36 | function incrementCounter() public { 37 | counter++; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contracts/VotingETH.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | contract VotingETH { 5 | struct Poll { 6 | address creator; 7 | uint256 quorumPercentage; 8 | uint256 expirationTime; 9 | PollStatus status; 10 | string description; 11 | } 12 | 13 | enum PollStatus { UNDEFINED, IN_PROGRESS, PASSED, REJECTED } 14 | 15 | Poll[] public polls; 16 | 17 | constructor() public { 18 | 19 | } 20 | 21 | modifier validPoll(uint256 _pollId) { 22 | require(_pollId < polls.length, "Not a valid poll ID"); 23 | _; 24 | } 25 | 26 | function createPoll(uint256 _quorumPercentage, string memory _description, uint256 _pollLength) public { 27 | require(_quorumPercentage <= 100, "Quorum percentage must be less than 100"); 28 | require(_pollLength > 0, "Poll length must be greater than 0"); 29 | polls.push(Poll({ 30 | creator: msg.sender, 31 | quorumPercentage: _quorumPercentage, 32 | expirationTime: now + _pollLength * 1 seconds, 33 | status: PollStatus.IN_PROGRESS, 34 | description: _description 35 | })); 36 | } 37 | 38 | function validateCastVote(uint256 _pollId) public validPoll(_pollId) { 39 | Poll memory poll = polls[_pollId]; 40 | require((poll.status == PollStatus.IN_PROGRESS) && (now < poll.expirationTime), "Invalid poll vote being cast to"); 41 | } 42 | 43 | function validateTallyPoll(uint256 _pollId, uint256 _talliedQuorum) public validPoll(_pollId) { 44 | Poll storage poll = polls[_pollId]; 45 | require((poll.status == PollStatus.IN_PROGRESS) && (now >= poll.expirationTime), "Invalid poll results being tallied"); 46 | poll.status = _talliedQuorum >= poll.quorumPercentage ? PollStatus.PASSED : PollStatus.REJECTED; 47 | } 48 | 49 | function getPolls() public returns (Poll[] memory) { 50 | return polls; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /contracts/impl/EnigmaCommon.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import { Bytes } from "../utils/Bytes.sol"; 5 | 6 | /** 7 | * @author Enigma 8 | * 9 | * This library contains the common structs and enums used throughout the Enigma codebase 10 | */ 11 | library EnigmaCommon { 12 | using Bytes for bytes; 13 | using Bytes for uint64; 14 | 15 | // ========================================== Structs ========================================== 16 | 17 | struct TaskRecord { 18 | address sender; // Sender of TaskRecord 19 | bytes32 inputsHash; // Inputs hash of encryptedFn, encryptedArgs, and contract address/preCodeHash 20 | bytes32 outputHash; // Output hash of task computation 21 | uint64 gasLimit; // ENG gas limit units 22 | uint64 gasPx; // ENG gas px in grains (10 ** 8) amount 23 | uint blockNumber; // Block number TaskRecord was mined 24 | TaskStatus status; // RecordUndefined: 0; RecordCreated: 1; ReceiptVerified: 2; ReceiptFailed: 3; ReceiptFailedETH: 4; ReceiptFailedReturn: 5 25 | bytes proof; // Signature of (taskId, inStateDeltaHash, outStateDeltaHash, ethCall) 26 | } 27 | 28 | struct Worker { 29 | address signer; // Enclave address 30 | WorkerStatus status; // Unregistered: 0, LoggedIn: 1, LoggedOut: 2 31 | bytes report; // Decided to store this as one RLP encoded attribute for easier external storage in the future 32 | uint256 balance; // ENG balance of worker 33 | WorkerLog[] workerLogs; // Logs containing info regarding updates in worker status 34 | } 35 | 36 | /** 37 | * The data representation of the worker parameters used as input for 38 | * the worker selection algorithm 39 | */ 40 | struct WorkersParams { 41 | uint firstBlockNumber; 42 | address[] workers; 43 | uint[] stakes; 44 | uint seed; 45 | } 46 | 47 | struct WorkerLog { 48 | WorkerLogType workerEventType; 49 | uint blockNumber; 50 | uint balance; 51 | } 52 | 53 | struct SecretContract { 54 | address owner; // Owner who deployed secret contract 55 | bytes32 preCodeHash; // Predeployed bytecode hash 56 | bytes32 codeHash; // Deployed bytecode hash 57 | bytes32[] stateDeltaHashes; // Array of state delta hashes 58 | SecretContractStatus status; // Undefined: 0, Deployed: 1 59 | // TODO: consider keeping an index of taskIds 60 | } 61 | 62 | // ========================================== Enums ========================================== 63 | 64 | enum TaskStatus {RecordUndefined, RecordCreated, ReceiptVerified, ReceiptFailed, ReceiptFailedETH, 65 | ReceiptFailedReturn} 66 | 67 | enum WorkerStatus {Unregistered, LoggedIn, LoggedOut} 68 | 69 | enum SecretContractStatus {Undefined, Deployed} 70 | 71 | enum WorkerLogType {Undefined, LogIn, LogOut, Compound} 72 | 73 | // ========================================== Shared Functions ========================================== 74 | 75 | /** 76 | * Append the length of a variable and the variable to an existing bytes buffer 77 | * 78 | * @param _message Bytes buffer being appended to 79 | * @param _var Bytes representation of value that needs to be concatenated to existing buffer 80 | * @return New bytes buffer 81 | */ 82 | function appendMessage(bytes memory _message, bytes memory _var) 83 | internal 84 | pure 85 | returns (bytes memory) 86 | { 87 | return (_message.concat(uint64(_var.length).toBytesFromUint64())).concat(_var); 88 | } 89 | 90 | /** 91 | * Append the length of an array to an existing bytes buffer 92 | * 93 | * @param _message Bytes buffer being appended to 94 | * @param _arraylength Length of array 95 | * @return New bytes buffer 96 | */ 97 | function appendMessageArrayLength(uint256 _arraylength, bytes memory _message) 98 | internal 99 | pure 100 | returns (bytes memory) 101 | { 102 | return _message.concat(uint64(_arraylength).toBytesFromUint64()); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /contracts/impl/EnigmaEvents.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | /** 5 | * @author Enigma 6 | * 7 | * Registers events to be emitted by the various functionalities of the Enigma codebase (need to be detailed here 8 | * as well as in the individual library as well 9 | */ 10 | contract EnigmaEvents { 11 | event Registered(address custodian, address signer); 12 | event WorkersParameterized(uint seed, uint256 firstBlockNumber, uint256 inclusionBlockNumber, address[] workers, 13 | uint[] stakes, uint nonce); 14 | event TaskRecordCreated(bytes32 taskId, bytes32 inputsHash, uint64 gasLimit, uint64 gasPx, address sender, 15 | uint blockNumber); 16 | event ReceiptVerified(bytes32 taskId, bytes32 stateDeltaHash, bytes32 outputHash, bytes32 scAddr, uint gasUsed, 17 | uint deltaHashIndex, bytes optionalEthereumData, address optionalEthereumContractAddress, address workerAddress, 18 | bytes sig); 19 | event ReceiptFailed(bytes32 taskId, bytes sig); 20 | event ReceiptFailedETH(bytes32 taskId, bytes sig); 21 | event TaskFeeReturned(bytes32 taskId); 22 | event DepositSuccessful(address from, uint value); 23 | event WithdrawSuccessful(address to, uint value); 24 | event SecretContractDeployed(bytes32 scAddr, bytes32 codeHash, bytes32 initStateDeltaHash); 25 | } 26 | -------------------------------------------------------------------------------- /contracts/impl/EnigmaState.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import { EnigmaCommon } from "./EnigmaCommon.sol"; 5 | import { ERC20 } from "../interfaces/ERC20.sol"; 6 | 7 | /** 8 | * @author Enigma 9 | * 10 | * Maintains the state of the Enigma contract (and the associated libraries) 11 | */ 12 | library EnigmaState { 13 | struct State { 14 | // The interface of the deployed ENG ERC20 token contract 15 | ERC20 engToken; 16 | 17 | // Epoch size in number of blocks 18 | uint epochSize; 19 | 20 | // Task timeout size in number of blocks 21 | uint taskTimeoutSize; 22 | 23 | /** 24 | * The signer address of the principal node 25 | * This must be set when deploying the contract and remains immutable 26 | * Since the signer address is derived from the public key of an 27 | * SGX enclave, this ensures that the principal node cannot be tempered 28 | * with or replaced. 29 | */ 30 | address principal; 31 | 32 | /** 33 | * The last 5 worker parameters 34 | * We keep a collection of worker parameters to account for latency issues. 35 | * A computation task might be conceivably given out at a certain block number 36 | * but executed at a later block in a different epoch. It follows that 37 | * the contract must have access to the worker parameters effective when giving 38 | * out the task, otherwise the selected worker would not match. We calculated 39 | * that keeping the last 5 items should be more than enough to account for 40 | * all latent tasks. Tasks results will be rejected past this limit. 41 | */ 42 | EnigmaCommon.WorkersParams[5] workersParams; 43 | 44 | // An address-based index of all registered worker 45 | address[] workerAddresses; 46 | // An address-based index of all secret contracts 47 | bytes32[] scAddresses; 48 | 49 | // A registry of all registered workers with their attributes 50 | mapping(address => EnigmaCommon.Worker) workers; 51 | 52 | // A registry of all tasks with their attributes 53 | mapping(bytes32 => EnigmaCommon.TaskRecord) tasks; 54 | 55 | // A registry of all deployed secret contracts with their attributes 56 | mapping(bytes32 => EnigmaCommon.SecretContract) contracts; 57 | 58 | // A mapping of number of tasks deployed for each address 59 | mapping(address => uint) userTaskDeployments; 60 | 61 | // TODO: do we keep tasks forever? if not, when do we delete them? 62 | uint stakingThreshold; 63 | uint workerGroupSize; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /contracts/impl/EnigmaStorage.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import { EnigmaState } from "./EnigmaState.sol"; 5 | 6 | /** 7 | * @author Enigma 8 | * 9 | * Storage for the Enigma state 10 | */ 11 | contract EnigmaStorage { 12 | EnigmaState.State state; 13 | } 14 | -------------------------------------------------------------------------------- /contracts/impl/Getters.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import {EnigmaCommon} from "./EnigmaCommon.sol"; 5 | import {EnigmaStorage} from "./EnigmaStorage.sol"; 6 | 7 | /** 8 | * @author Enigma 9 | * 10 | * Getter functions to be used by Enigma library to access state variables 11 | */ 12 | contract Getters is EnigmaStorage { 13 | /** 14 | * Get signing address of calling worker 15 | * 16 | * @return Signing address 17 | */ 18 | function getSigningAddress() public view returns (address) { 19 | return state.workers[msg.sender].signer; 20 | } 21 | 22 | /** 23 | * Get Worker struct from a given worker's ethereum address 24 | * 25 | * @param _worker Worker's ethereum address 26 | * @return Worker struct 27 | */ 28 | function getWorker(address _worker) public view returns (EnigmaCommon.Worker memory) { 29 | return state.workers[_worker]; 30 | } 31 | 32 | /** 33 | * Get Worker struct from a given worker's signing address 34 | * 35 | * @param _signer Worker's signing address 36 | * @return Ethereum address 37 | * @return Worker struct 38 | */ 39 | function getWorkerFromSigningAddress(address _signer) public view returns (address, EnigmaCommon.Worker memory) { 40 | address account; 41 | EnigmaCommon.Worker memory worker; 42 | for (uint i = 0; i < state.workerAddresses.length; i++) { 43 | worker = state.workers[state.workerAddresses[i]]; 44 | if (worker.signer == _signer) { 45 | account = state.workerAddresses[i]; 46 | break; 47 | } 48 | } 49 | return (account, worker); 50 | } 51 | 52 | /** 53 | * Get the current number/index (used as unique nonce value) of task deployments for a given user user 54 | * 55 | * @param _sender Task sender's ethereum address 56 | * @return Current number for task deployments for user 57 | */ 58 | function getUserTaskDeployments(address _sender) public view returns (uint) { 59 | return state.userTaskDeployments[_sender]; 60 | } 61 | 62 | /** 63 | * Get the epoch block size 64 | * 65 | * @return Epoch size 66 | */ 67 | function getEpochSize() public view returns (uint) { 68 | return state.epochSize; 69 | } 70 | 71 | /** 72 | * Get the task timeout size 73 | * 74 | * @return task timeout 75 | */ 76 | function getTaskTimeoutSize() public view returns (uint) { 77 | return state.taskTimeoutSize; 78 | } 79 | 80 | /** 81 | * Get a TaskRecord struct given a particular task's ID 82 | * 83 | * @param _taskId Unique identifier for a given task 84 | * @return TaskRecord struct 85 | */ 86 | function getTaskRecord(bytes32 _taskId) public view returns (EnigmaCommon.TaskRecord memory) { 87 | return state.tasks[_taskId]; 88 | } 89 | 90 | /** 91 | * Get a SecretContract struct given a particular secret contract address 92 | * 93 | * @param _scAddr Secret contract address 94 | * @return SecretContract struct 95 | */ 96 | function getSecretContract(bytes32 _scAddr) public view returns (EnigmaCommon.SecretContract memory) { 97 | return state.contracts[_scAddr]; 98 | } 99 | 100 | /** 101 | * Get epoch-based history of worker params information 102 | * 103 | * @return Array of WorkersParams structs 104 | */ 105 | function getWorkersParams() public view returns (EnigmaCommon.WorkersParams[5] memory) { 106 | return state.workersParams; 107 | } 108 | 109 | /** 110 | * Get all secret contract addresses 111 | * 112 | * @return Array of secret contract addresses 113 | */ 114 | function getAllSecretContractAddresses() public view returns (bytes32[] memory) { 115 | return state.scAddresses; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /contracts/impl/PrincipalImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import "openzeppelin-solidity/contracts/math/SafeMath.sol"; 5 | import "openzeppelin-solidity/contracts/cryptography/ECDSA.sol"; 6 | 7 | import { EnigmaCommon } from "./EnigmaCommon.sol"; 8 | import { EnigmaState } from "./EnigmaState.sol"; 9 | import { WorkersImpl } from "./WorkersImpl.sol"; 10 | import { Bytes } from "../utils/Bytes.sol"; 11 | 12 | /** 13 | * @author Enigma 14 | * 15 | * Library that maintains functionality associated with Principal node 16 | */ 17 | library PrincipalImpl { 18 | using SafeMath for uint256; 19 | using ECDSA for bytes32; 20 | using Bytes for bytes; 21 | using Bytes for bytes32; 22 | using Bytes for uint256; 23 | using Bytes for address; 24 | 25 | event WorkersParameterized(uint seed, uint256 firstBlockNumber, uint256 inclusionBlockNumber, address[] workers, 26 | uint[] stakes, uint nonce); 27 | 28 | function setWorkersParamsImpl(EnigmaState.State storage state, uint _blockNumber, uint _seed, bytes memory _sig) 29 | public 30 | { 31 | // Reparameterizing workers with a new seed 32 | // This should be called for each epoch by the Principal node 33 | 34 | // We assume that the Principal is always the first registered node 35 | require(state.workers[msg.sender].signer == state.principal, "Only the Principal can update the seed"); 36 | require(_blockNumber - WorkersImpl.getFirstBlockNumberImpl(state, _blockNumber) >= state.epochSize, 37 | "Already called during this epoch"); 38 | 39 | // Create a new workers parameters item for the specified seed. 40 | // The workers parameters list is a sort of cache, it never grows beyond its limit. 41 | // If the list is full, the new item will replace the item assigned to the lowest block number. 42 | uint paramIndex = 0; 43 | for (uint pi = 0; pi < state.workersParams.length; pi++) { 44 | // Find an empty slot in the array, if full use the lowest block number 45 | if (state.workersParams[pi].firstBlockNumber == 0) { 46 | paramIndex = pi; 47 | break; 48 | } else if (state.workersParams[pi].firstBlockNumber < state.workersParams[paramIndex].firstBlockNumber) { 49 | paramIndex = pi; 50 | } 51 | } 52 | EnigmaCommon.WorkersParams storage workerParams = state.workersParams[paramIndex]; 53 | workerParams.firstBlockNumber = block.number; 54 | workerParams.seed = _seed; 55 | 56 | (workerParams.workers, workerParams.stakes) = getActiveWorkersImpl(state, _blockNumber); 57 | 58 | // Verify the principal's signature 59 | bytes memory message; 60 | message = EnigmaCommon.appendMessage(message, _seed.toBytes()); 61 | message = EnigmaCommon.appendMessage(message, state.userTaskDeployments[msg.sender].toBytes()); 62 | message = EnigmaCommon.appendMessageArrayLength(workerParams.workers.length, message); 63 | for (uint i = 0; i < workerParams.workers.length; i++) { 64 | message = EnigmaCommon.appendMessage(message, workerParams.workers[i].toBytes()); 65 | } 66 | message = EnigmaCommon.appendMessageArrayLength(workerParams.stakes.length, message); 67 | for (uint j = 0; j < workerParams.stakes.length; j++) { 68 | message = EnigmaCommon.appendMessage(message, workerParams.stakes[j].toBytes()); 69 | } 70 | bytes32 msgHash = keccak256(message); 71 | require(msgHash.recover(_sig) == state.principal, "Invalid signature"); 72 | 73 | for (uint wi = 0; wi < workerParams.workers.length; wi++) { 74 | EnigmaCommon.Worker storage worker = state.workers[workerParams.workers[wi]]; 75 | worker.workerLogs.push(EnigmaCommon.WorkerLog({ 76 | workerEventType: EnigmaCommon.WorkerLogType.Compound, 77 | blockNumber: block.number, 78 | balance: worker.balance 79 | })); 80 | } 81 | 82 | emit WorkersParameterized(_seed, block.number, _blockNumber, workerParams.workers, 83 | workerParams.stakes, state.userTaskDeployments[msg.sender]); 84 | state.userTaskDeployments[msg.sender]++; 85 | } 86 | 87 | function getActiveWorkersImpl(EnigmaState.State storage state, uint _blockNumber) 88 | public 89 | view 90 | returns (address[] memory, uint[] memory) 91 | { 92 | uint maxLength = state.workerAddresses.length; 93 | address[] memory activeWorkerAddressesFull = new address[](maxLength); 94 | uint[] memory activeWorkerStakesFull = new uint[](maxLength); 95 | uint filteredCount; 96 | 97 | for (uint i = 0; i < maxLength; i++) { 98 | EnigmaCommon.Worker memory worker = state.workers[state.workerAddresses[i]]; 99 | EnigmaCommon.WorkerLog memory workerLog = WorkersImpl.getLatestWorkerLogImpl(worker, _blockNumber); 100 | if (((workerLog.workerEventType == EnigmaCommon.WorkerLogType.LogIn) || 101 | (workerLog.workerEventType == EnigmaCommon.WorkerLogType.Compound)) && 102 | worker.signer != state.principal) 103 | { 104 | activeWorkerAddressesFull[filteredCount] = worker.signer; 105 | activeWorkerStakesFull[filteredCount] = workerLog.balance; 106 | filteredCount++; 107 | } 108 | } 109 | 110 | address[] memory activeWorkerAddresses = new address[](filteredCount); 111 | uint[] memory activeWorkerStakes = new uint[](filteredCount); 112 | for (uint ic = 0; ic < filteredCount; ic++) { 113 | activeWorkerAddresses[ic] = activeWorkerAddressesFull[ic]; 114 | activeWorkerStakes[ic] = activeWorkerStakesFull[ic]; 115 | } 116 | 117 | return (activeWorkerAddresses, activeWorkerStakes); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /contracts/impl/PrincipalImplSimulation.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import "openzeppelin-solidity/contracts/math/SafeMath.sol"; 5 | import "openzeppelin-solidity/contracts/cryptography/ECDSA.sol"; 6 | 7 | import { EnigmaCommon } from "./EnigmaCommon.sol"; 8 | import { EnigmaState } from "./EnigmaState.sol"; 9 | import { WorkersImplSimulation } from "./WorkersImplSimulation.sol"; 10 | import { Bytes } from "../utils/Bytes.sol"; 11 | 12 | /** 13 | * @author Enigma 14 | * 15 | * Library that maintains functionality associated with Principal node 16 | */ 17 | library PrincipalImplSimulation { 18 | using SafeMath for uint256; 19 | using ECDSA for bytes32; 20 | using Bytes for bytes; 21 | using Bytes for bytes32; 22 | using Bytes for uint256; 23 | using Bytes for address; 24 | 25 | event WorkersParameterized(uint seed, uint256 firstBlockNumber, uint256 inclusionBlockNumber, address[] workers, 26 | uint[] stakes, uint nonce); 27 | 28 | function setWorkersParamsImpl(EnigmaState.State storage state, uint _blockNumber, uint _seed, bytes memory _sig) 29 | public 30 | { 31 | // Reparameterizing workers with a new seed 32 | // This should be called for each epoch by the Principal node 33 | 34 | // We assume that the Principal is always the first registered node 35 | require(state.workers[msg.sender].signer == state.principal, "Only the Principal can update the seed"); 36 | require(_blockNumber - WorkersImplSimulation.getFirstBlockNumberImpl(state, _blockNumber) >= state.epochSize, 37 | "Already called during this epoch"); 38 | 39 | // Create a new workers parameters item for the specified seed. 40 | // The workers parameters list is a sort of cache, it never grows beyond its limit. 41 | // If the list is full, the new item will replace the item assigned to the lowest block number. 42 | uint paramIndex = 0; 43 | for (uint pi = 0; pi < state.workersParams.length; pi++) { 44 | // Find an empty slot in the array, if full use the lowest block number 45 | if (state.workersParams[pi].firstBlockNumber == 0) { 46 | paramIndex = pi; 47 | break; 48 | } else if (state.workersParams[pi].firstBlockNumber < state.workersParams[paramIndex].firstBlockNumber) { 49 | paramIndex = pi; 50 | } 51 | } 52 | EnigmaCommon.WorkersParams storage workerParams = state.workersParams[paramIndex]; 53 | workerParams.firstBlockNumber = block.number; 54 | workerParams.seed = _seed; 55 | 56 | (workerParams.workers, workerParams.stakes) = getActiveWorkersImpl(state, _blockNumber); 57 | 58 | // Verify the principal's signature 59 | bytes memory message; 60 | message = EnigmaCommon.appendMessage(message, _seed.toBytes()); 61 | message = EnigmaCommon.appendMessage(message, state.userTaskDeployments[msg.sender].toBytes()); 62 | message = EnigmaCommon.appendMessageArrayLength(workerParams.workers.length, message); 63 | for (uint i = 0; i < workerParams.workers.length; i++) { 64 | message = EnigmaCommon.appendMessage(message, workerParams.workers[i].toBytes()); 65 | } 66 | message = EnigmaCommon.appendMessageArrayLength(workerParams.stakes.length, message); 67 | for (uint j = 0; j < workerParams.stakes.length; j++) { 68 | message = EnigmaCommon.appendMessage(message, workerParams.stakes[j].toBytes()); 69 | } 70 | bytes32 msgHash = keccak256(message); 71 | require(msgHash.recover(_sig) == state.principal, "Invalid signature"); 72 | 73 | for (uint wi = 0; wi < workerParams.workers.length; wi++) { 74 | EnigmaCommon.Worker storage worker = state.workers[workerParams.workers[wi]]; 75 | worker.workerLogs.push(EnigmaCommon.WorkerLog({ 76 | workerEventType: EnigmaCommon.WorkerLogType.Compound, 77 | blockNumber: block.number, 78 | balance: worker.balance 79 | })); 80 | } 81 | 82 | emit WorkersParameterized(_seed, block.number, _blockNumber, workerParams.workers, 83 | workerParams.stakes, state.userTaskDeployments[msg.sender]); 84 | state.userTaskDeployments[msg.sender]++; 85 | } 86 | 87 | function getActiveWorkersImpl(EnigmaState.State storage state, uint _blockNumber) 88 | public 89 | view 90 | returns (address[] memory, uint[] memory) 91 | { 92 | uint maxLength = state.workerAddresses.length; 93 | address[] memory activeWorkerAddressesFull = new address[](maxLength); 94 | uint[] memory activeWorkerStakesFull = new uint[](maxLength); 95 | uint filteredCount; 96 | 97 | for (uint i = 0; i < maxLength; i++) { 98 | EnigmaCommon.Worker memory worker = state.workers[state.workerAddresses[i]]; 99 | EnigmaCommon.WorkerLog memory workerLog = WorkersImplSimulation.getLatestWorkerLogImpl(worker, _blockNumber); 100 | if (((workerLog.workerEventType == EnigmaCommon.WorkerLogType.LogIn) || 101 | (workerLog.workerEventType == EnigmaCommon.WorkerLogType.Compound)) && 102 | worker.signer != state.principal) 103 | { 104 | activeWorkerAddressesFull[filteredCount] = worker.signer; 105 | activeWorkerStakesFull[filteredCount] = workerLog.balance; 106 | filteredCount++; 107 | } 108 | } 109 | 110 | address[] memory activeWorkerAddresses = new address[](filteredCount); 111 | uint[] memory activeWorkerStakes = new uint[](filteredCount); 112 | for (uint ic = 0; ic < filteredCount; ic++) { 113 | activeWorkerAddresses[ic] = activeWorkerAddressesFull[ic]; 114 | activeWorkerStakes[ic] = activeWorkerStakesFull[ic]; 115 | } 116 | 117 | return (activeWorkerAddresses, activeWorkerStakes); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /contracts/impl/SecretContractImpl.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | import "openzeppelin-solidity/contracts/math/SafeMath.sol"; 5 | import "openzeppelin-solidity/contracts/cryptography/ECDSA.sol"; 6 | 7 | import { EnigmaCommon } from "./EnigmaCommon.sol"; 8 | import { EnigmaState } from "./EnigmaState.sol"; 9 | import "../utils/SolRsaVerify.sol"; 10 | 11 | /** 12 | * @author Enigma 13 | * 14 | * Library that maintains functionality associated with secret contracts 15 | */ 16 | library SecretContractImpl { 17 | using SafeMath for uint256; 18 | using ECDSA for bytes32; 19 | 20 | function countStateDeltasImpl(EnigmaState.State storage state, bytes32 _scAddr) 21 | public 22 | view 23 | returns (uint) 24 | { 25 | return state.contracts[_scAddr].stateDeltaHashes.length; 26 | } 27 | 28 | function countSecretContractsImpl(EnigmaState.State storage state) 29 | public 30 | view 31 | returns (uint) 32 | { 33 | return state.scAddresses.length; 34 | } 35 | 36 | function getSecretContractAddressesImpl(EnigmaState.State storage state, uint _start, uint _stop) 37 | public 38 | view 39 | returns (bytes32[] memory) 40 | { 41 | if (_stop == 0) { 42 | _stop = state.scAddresses.length; 43 | } 44 | bytes32[] memory addresses = new bytes32[](_stop.sub(_start)); 45 | uint pos = 0; 46 | for (uint i = _start; i < _stop; i++) { 47 | addresses[pos] = state.scAddresses[i]; 48 | pos++; 49 | } 50 | return addresses; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /contracts/interfaces/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | /** 5 | * @author Enigma 6 | * 7 | * ERC20 interface to wrap the EnigmaToken contract 8 | */ 9 | interface ERC20 { 10 | function allowance(address owner, address spender) external view returns (uint256); 11 | 12 | function transferFrom(address from, address to, uint256 value) external returns (bool); 13 | 14 | function approve(address spender, uint256 value) external returns (bool); 15 | 16 | function totalSupply() external view returns (uint256); 17 | 18 | function balanceOf(address who) external view returns (uint256); 19 | 20 | function transfer(address to, uint256 value) external returns (bool); 21 | 22 | event Transfer(address indexed from, address indexed to, uint256 value); 23 | event Approval(address indexed owner, address indexed spender, uint256 value); 24 | } 25 | -------------------------------------------------------------------------------- /contracts/interfaces/IEnigma.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | pragma experimental ABIEncoderV2; 3 | 4 | interface IEnigma { 5 | function register(address _signer, bytes calldata _report, bytes calldata _signature) external; 6 | function getActiveWorkers(uint _blockNumber) external view returns (address[] memory, uint[] memory); 7 | function setWorkersParams(uint _blockNumber, uint _seed, bytes calldata _sig) external; 8 | function countSecretContracts() external view returns (uint); 9 | function getSecretContractAddresses(uint _start, uint _stop) external view returns (bytes32[] memory); 10 | function getAllSecretContractAddresses() external view returns (bytes32[] memory); 11 | function getSigningAddress() external view returns (address); 12 | } 13 | -------------------------------------------------------------------------------- /contracts/utils/Base64.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /** 4 | * @title Base64 encoding and decoding 5 | * Solidity port of the original Javascript below 6 | */ 7 | 8 | /** 9 | * Copyright (C) 1999 Masanao Izumo 10 | * Version: 1.0 11 | * LastModified: Dec 25 1999 12 | * This library is free. You can redistribute it and/or modify it. 13 | * Source: http://code.google.com/p/gflot/source/browse/trunk/flot/base64.js 14 | */ 15 | 16 | library Base64 { 17 | 18 | // bytes constant base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 19 | 20 | function init_base64DecodeChars() internal pure returns (int8[128] memory base64DecodeChars){ 21 | base64DecodeChars = [ 22 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 25 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, 26 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 27 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 28 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 29 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1]; 30 | } 31 | 32 | // function encode(bytes memory source) internal pure returns (bytes memory out){ 33 | // uint i=0; 34 | // uint o=0; 35 | // uint len = source.length; 36 | // uint8 c1; 37 | // uint8 c2; 38 | // uint8 c3; 39 | // out = new bytes(source.length*2); 40 | // while(i= len' 27 | function equals(uint addr, uint len, bytes memory bts) internal pure returns (bool equal) { 28 | require(bts.length >= len); 29 | uint addr2; 30 | assembly { 31 | addr2 := add(bts, /*BYTES_HEADER_SIZE*/32) 32 | } 33 | return equals(addr, addr2, len); 34 | } 35 | 36 | // Allocates 'numBytes' bytes in memory. This will prevent the Solidity compiler 37 | // from using this area of memory. It will also initialize the area by setting 38 | // each byte to '0'. 39 | function allocate(uint numBytes) internal pure returns (uint addr) { 40 | // Take the current value of the free memory pointer, and upae. 41 | assembly { 42 | addr := mload(/*FREE_MEM_PTR*/0x40) 43 | mstore(/*FREE_MEM_PTR*/0x40, add(addr, numBytes)) 44 | } 45 | uint words = (numBytes + WORD_SIZE - 1) / WORD_SIZE; 46 | for (uint i = 0; i < words; i++) { 47 | assembly { 48 | mstore(add(addr, mul(i, /*WORD_SIZE*/32)), 0) 49 | } 50 | } 51 | } 52 | 53 | // Copy 'len' bytes from memory address 'src', to address 'dest'. 54 | // This function does not check the or destination, it only copies 55 | // the bytes. 56 | function copy(uint src, uint dest, uint len) internal pure { 57 | // Copy word-length chunks while possible 58 | for (; len >= WORD_SIZE; len -= WORD_SIZE) { 59 | assembly { 60 | mstore(dest, mload(src)) 61 | } 62 | dest += WORD_SIZE; 63 | src += WORD_SIZE; 64 | } 65 | 66 | // Copy remaining bytes 67 | uint mask = 256 ** (WORD_SIZE - len) - 1; 68 | assembly { 69 | let srcpart := and(mload(src), not(mask)) 70 | let destpart := and(mload(dest), mask) 71 | mstore(dest, or(destpart, srcpart)) 72 | } 73 | } 74 | 75 | // Returns a memory pointer to the provided bytes array. 76 | function ptr(bytes memory bts) internal pure returns (uint addr) { 77 | assembly { 78 | addr := bts 79 | } 80 | } 81 | 82 | // Returns a memory pointer to the data portion of the provided bytes array. 83 | function dataPtr(bytes memory bts) internal pure returns (uint addr) { 84 | assembly { 85 | addr := add(bts, /*BYTES_HEADER_SIZE*/32) 86 | } 87 | } 88 | 89 | // This function does the same as 'dataPtr(bytes memory)', but will also return the 90 | // length of the provided bytes array. 91 | function fromBytes(bytes memory bts) internal pure returns (uint addr, uint len) { 92 | len = bts.length; 93 | assembly { 94 | addr := add(bts, /*BYTES_HEADER_SIZE*/32) 95 | } 96 | } 97 | 98 | // Creates a 'bytes memory' variable from the memory address 'addr', with the 99 | // length 'len'. The function will allocate new memory for the bytes array, and 100 | // the 'len bytes starting at 'addr' will be copied into that new memory. 101 | function toBytes(uint addr, uint len) internal pure returns (bytes memory bts) { 102 | bts = new bytes(len); 103 | uint btsptr; 104 | assembly { 105 | btsptr := add(bts, /*BYTES_HEADER_SIZE*/32) 106 | } 107 | copy(addr, btsptr, len); 108 | } 109 | 110 | // Get the word stored at memory address 'addr' as a 'uint'. 111 | function toUint(uint addr) internal pure returns (uint n) { 112 | assembly { 113 | n := mload(addr) 114 | } 115 | } 116 | 117 | // Get the word stored at memory address 'addr' as a 'bytes32'. 118 | function toBytes32(uint addr) internal pure returns (bytes32 bts) { 119 | assembly { 120 | bts := mload(addr) 121 | } 122 | } 123 | 124 | /* 125 | // Get the byte stored at memory address 'addr' as a 'byte'. 126 | function toByte(uint addr, uint8 index) internal pure returns (byte b) { 127 | require(index < WORD_SIZE); 128 | uint8 n; 129 | assembly { 130 | n := byte(index, mload(addr)) 131 | } 132 | b = byte(n); 133 | } 134 | */ 135 | } 136 | -------------------------------------------------------------------------------- /contracts/utils/SolRsaVerify.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | /* 4 | Copyright 2016, Adrià Massanet 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | 19 | Checked results with FIPS test vectors 20 | https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/dss/186-2rsatestvectors.zip 21 | file SigVer15_186-3.rsp 22 | 23 | */ 24 | 25 | library SolRsaVerify { 26 | 27 | function memcpy(uint _dest, uint _src, uint _len) pure internal { 28 | // Copy word-length chunks while possible 29 | for ( ;_len >= 32; _len -= 32) { 30 | assembly { 31 | mstore(_dest, mload(_src)) 32 | } 33 | _dest += 32; 34 | _src += 32; 35 | } 36 | 37 | // Copy remaining bytes 38 | uint mask = 256 ** (32 - _len) - 1; 39 | assembly { 40 | let srcpart := and(mload(_src), not(mask)) 41 | let destpart := and(mload(_dest), mask) 42 | mstore(_dest, or(destpart, srcpart)) 43 | } 44 | } 45 | 46 | 47 | function join( 48 | bytes memory _s, bytes memory _e, bytes memory _m 49 | ) pure internal returns (bytes memory) { 50 | uint inputLen = 0x60+_s.length+_e.length+_m.length; 51 | 52 | uint slen = _s.length; 53 | uint elen = _e.length; 54 | uint mlen = _m.length; 55 | uint sptr; 56 | uint eptr; 57 | uint mptr; 58 | uint inputPtr; 59 | 60 | bytes memory input = new bytes(inputLen); 61 | assembly { 62 | sptr := add(_s,0x20) 63 | eptr := add(_e,0x20) 64 | mptr := add(_m,0x20) 65 | mstore(add(input,0x20),slen) 66 | mstore(add(input,0x40),elen) 67 | mstore(add(input,0x60),mlen) 68 | inputPtr := add(input,0x20) 69 | } 70 | memcpy(inputPtr+0x60,sptr,_s.length); 71 | memcpy(inputPtr+0x60+_s.length,eptr,_e.length); 72 | memcpy(inputPtr+0x60+_s.length+_e.length,mptr,_m.length); 73 | 74 | return input; 75 | } 76 | 77 | /** @dev Verifies a PKCSv1.5 SHA256 signature 78 | * @param _sha256 is the sha256 of the data 79 | * @param _s is the signature 80 | * @param _e is the exponent 81 | * @param _m is the modulus 82 | * @return 0 if success, >0 otherwise 83 | */ 84 | function pkcs1Sha256Verify( 85 | bytes32 _sha256, 86 | bytes memory _s, bytes memory _e, bytes memory _m 87 | ) internal view returns (uint) { 88 | 89 | uint8[19] memory sha256Prefix = [ 90 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 91 | ]; 92 | 93 | require(_m.length >= sha256Prefix.length+_sha256.length+11); 94 | 95 | uint i; 96 | 97 | /// decipher 98 | bytes memory input = join(_s,_e,_m); 99 | uint inputlen = input.length; 100 | 101 | uint decipherlen = _m.length; 102 | bytes memory decipher = new bytes(decipherlen); 103 | assembly { 104 | pop(staticcall(sub(gas, 2000), 5, add(input,0x20), inputlen, add(decipher,0x20), decipherlen)) 105 | } 106 | 107 | /// 0x00 || 0x01 || PS || 0x00 || DigestInfo 108 | /// PS is padding filled with 0xff 109 | // DigestInfo ::= SEQUENCE { 110 | // digestAlgorithm AlgorithmIdentifier, 111 | // digest OCTET STRING 112 | // } 113 | 114 | uint paddingLen = decipherlen - 3 - sha256Prefix.length - 32; 115 | 116 | if (decipher[0] != 0 || uint8(decipher[1]) != 1) { 117 | return 1; 118 | } 119 | for (i = 2;i<2+paddingLen;i++) { 120 | if (decipher[i] != 0xff) { 121 | return 2; 122 | } 123 | } 124 | if (decipher[2+paddingLen] != 0) { 125 | return 3; 126 | } 127 | for (i = 0;i0 otherwise 147 | */ 148 | function pkcs1Sha256VerifyRaw( 149 | bytes memory _data, 150 | bytes memory _s, bytes memory _e, bytes memory _m 151 | ) internal view returns (uint) { 152 | return pkcs1Sha256Verify(sha256(_data),_s,_e,_m); 153 | } 154 | 155 | } -------------------------------------------------------------------------------- /deploy-ganache.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | rm -rf build 3 | darq-truffle compile 4 | darq-truffle migrate --reset --network $1 5 | darq-truffle test --network $1 6 | -------------------------------------------------------------------------------- /enigma-js/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /enigma-js/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = LF 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /enigma-js/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "env": { 4 | "browser": true, 5 | "es6": true, 6 | "node": true 7 | }, 8 | 9 | "globals": { 10 | "document": false, 11 | "escape": false, 12 | "navigator": false, 13 | "unescape": false, 14 | "window": false, 15 | "describe": true, 16 | "before": true, 17 | "it": true, 18 | "expect": true, 19 | "sinon": true 20 | }, 21 | 22 | "parser": "babel-eslint", 23 | 24 | "plugins": [ 25 | 26 | ], 27 | 28 | "extends":"google", 29 | 30 | "rules": { 31 | "camelcase": [2, { "properties": "always" }], 32 | "max-len": [2, 120, 4], 33 | "new-cap": ["error", { "capIsNew": false }] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /enigma-js/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | # Remove some common IDE working directories 30 | .idea 31 | .vscode 32 | 33 | .DS_Store 34 | node.js 35 | -------------------------------------------------------------------------------- /enigma-js/.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | # Remove some common IDE working directories 30 | .idea 31 | .vscode 32 | 33 | .DS_Store 34 | 35 | test 36 | .nvmrc 37 | .eslintrc 38 | .nyc_output 39 | jest.init.js 40 | .editorconfig 41 | *.map -------------------------------------------------------------------------------- /enigma-js/.nvmrc: -------------------------------------------------------------------------------- 1 | v6.10 2 | -------------------------------------------------------------------------------- /enigma-js/README.md: -------------------------------------------------------------------------------- 1 | # Enigma JS 2 | 3 | A universal Javascript client library for the Enigma Network 4 | 5 | ## Features 6 | 7 | * Webpack 4 based. 8 | * ES6 as a source. 9 | * Exports in a [umd](https://github.com/umdjs/umd) format so the library works everywhere. 10 | * ES6 test setup with [Jest](https://jestjs.io/). 11 | * Linting with [ESLint](http://eslint.org/). 12 | 13 | ## Process 14 | 15 | ``` 16 | ES6 source files 17 | | 18 | | 19 | webpack 20 | | 21 | +--- babel, eslint 22 | | 23 | ready to use 24 | library 25 | in umd format 26 | ``` 27 | 28 | *Have in mind that you have to build the library before publishing. The files under the `lib` folder are the ones that should be distributed.* 29 | 30 | ## Getting started 31 | 32 | 1. Install the following packages globally: 33 | ``` 34 | yarn global add ganache-cli truffle 35 | ``` 36 | 2. Install the package dependencies 37 | 38 | * On the parent folder, run `yarn install` to install the project dependencies. 39 | 40 | 2. Install the client library dependencies 41 | 42 | * Run `yarn install` to get the client library dependencies on the current folder 43 | 44 | 3. [OPTIONAL] Development mode 45 | 46 | * Having all the dependencies installed run `yarn dev`. This command will generate an non-minified version of the library and will run a watcher so you get the compilation on file change. 47 | 48 | 4. Running the tests 49 | 50 | * Open one terminal at the root of the parent folder `enigma-contract` run the following: 51 | ``` 52 | $ ganache-cli -p 9545 -i 4447 & 53 | ``` 54 | * And once Ganache-cli has started, run: 55 | ``` 56 | $ truffle migrate --reset 57 | ``` 58 | * On a separate terminal run: 59 | ``` 60 | yarn test 61 | ``` 62 | 63 | 5. Build the library 64 | 65 | * Run `yarn build` to produce minified version of the library. It will check code quality before building (ESLint) and it will also run all tests afterwards (see prior step) and output a code coverage report. 66 | 67 | 68 | ## Scripts 69 | 70 | * `yarn build` - produces production version of the library under the `lib` folder 71 | * `yarn dev` - produces development version of the library and runs a watcher 72 | * `yarn test` - well ... it runs the tests :) 73 | * `yarn test:watch` - same as above but in a watch mode 74 | -------------------------------------------------------------------------------- /enigma-js/jest.init.js: -------------------------------------------------------------------------------- 1 | // Fixes error "ReferenceError: regeneratorRuntime is not defined" from Jest 2 | // See: https://github.com/facebook/jest/issues/3126#issuecomment-345949328 3 | import "core-js/stable"; 4 | import "regenerator-runtime/runtime"; -------------------------------------------------------------------------------- /enigma-js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "enigma-js", 3 | "version": "0.3.0", 4 | "description": "The Javascript client for the Enigma Network", 5 | "main": "lib/enigma-js.js", 6 | "scripts": { 7 | "build": "webpack --env dev && webpack --env build && npm run test", 8 | "dev": "webpack --progress --colors --watch --env dev", 9 | "test": "jest", 10 | "test:integration": "jest -c=test/integrationTests/jest.config.js", 11 | "test:watch": "jest --watch", 12 | "report-coverage": "codecov" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git@github.com:enigmampc/enigma-contract.git" 17 | }, 18 | "keywords": [ 19 | "webpack", 20 | "es6", 21 | "starter", 22 | "library", 23 | "universal", 24 | "umd", 25 | "commonjs" 26 | ], 27 | "author": "Frederic Fortier ", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "" 31 | }, 32 | "homepage": "https://enigma.co", 33 | "dependencies": { 34 | "any-promise": "^1.3.0", 35 | "axios": "0.18.1", 36 | "body-parser": "^1.18.3", 37 | "buffer": "^5.1.0", 38 | "connect": "^3.6.6", 39 | "core-js": "^3.1.4", 40 | "create-file-webpack": "^1.0.2", 41 | "elliptic": "6.4.0", 42 | "eth-crypto": "^1.2.2", 43 | "ethereumjs-abi": "^0.6.5", 44 | "ethereumjs-util": "^6.0.0", 45 | "eventemitter3": "^3.1.0", 46 | "filereader": "^0.10.3", 47 | "jayson": "^3.0.1", 48 | "jsbi": "^2.0.5", 49 | "net": "^1.0.2", 50 | "node-fetch": "^2.3.0", 51 | "node-forge": "^0.7.6", 52 | "openzeppelin-solidity": "2.1", 53 | "regenerator-runtime": "^0.13.3", 54 | "retry": "^0.12.0", 55 | "rlp": "2.1.0", 56 | "source-map-support": "^0.5.9", 57 | "tls": "0.0.1", 58 | "truffle-contract": "^4.0.0", 59 | "uuid": "^3.3.2", 60 | "web3-utils": "1.0.0-beta.37", 61 | "webpack-node-externals": "^1.7.2", 62 | "whatwg-fetch": "^3.0.0" 63 | }, 64 | "devDependencies": { 65 | "@babel/cli": "^7.0.0-beta.51", 66 | "@babel/core": "^7.2.0", 67 | "@babel/preset-env": "^7.0.0", 68 | "@babel/register": "^7.0.0", 69 | "babel-core": "^7.0.0-bridge.0", 70 | "babel-eslint": "^9.0.0", 71 | "babel-jest": "^23.6.0", 72 | "babel-loader": "^8.0.0-beta.4", 73 | "chai": "^4.1.2", 74 | "chai-events": "0.0.1", 75 | "codecov": "^3.5.0", 76 | "dockerode": "^2.5.8", 77 | "eslint": "^5.4.0", 78 | "eslint-config-google": "^0.9.1", 79 | "eslint-loader": "^2.0.0", 80 | "jest": "^24.8.0", 81 | "jest-circus": "^24.8.0", 82 | "jsdom": "11.11.0", 83 | "jsdom-global": "3.0.2", 84 | "mock-local-storage": "^1.1.7", 85 | "uglifyjs-webpack-plugin": "^1.2.7", 86 | "web3": "1.0.0-beta.37", 87 | "webpack": "^4.12.2", 88 | "webpack-cli": "^3.0.8", 89 | "yargs": "^10.0.3" 90 | }, 91 | "jest": { 92 | "setupFiles": [ 93 | "/jest.init.js" 94 | ], 95 | "collectCoverage": true, 96 | "coverageDirectory": "./coverage/", 97 | "collectCoverageFrom": [ 98 | "src/**/*.{js,jsx}", 99 | "!src/index.js" 100 | ], 101 | "testPathIgnorePatterns": [ 102 | "/node_modules/", 103 | "/test/integrationTests/" 104 | ], 105 | "testRunner": "jest-circus/runner" 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /enigma-js/src/Server.js: -------------------------------------------------------------------------------- 1 | import jayson from 'jayson'; 2 | import cors from 'cors'; 3 | import connect from 'connect'; 4 | import bodyParser from 'body-parser'; 5 | import web3Utils from 'web3-utils'; 6 | import data from '../test/data'; 7 | import EthCrypto from 'eth-crypto'; 8 | import utils from './enigma-utils'; 9 | 10 | export default class RPCServer { 11 | constructor() { 12 | let _counter = 0; 13 | this.app = connect(); 14 | this.serverInstance = null; 15 | this.resetCounter = () => { 16 | _counter = 0; 17 | }; 18 | this.server = jayson.server({ 19 | getWorkerEncryptionKey: function(args, callback) { 20 | if(args.userPubKey && args.workerAddress){ 21 | const worker = data.workers.find((w) => w[0] === '0x' + args.workerAddress); 22 | const identity = EthCrypto.createIdentity(); 23 | // see the corresponding implementation in Enigma.js for an explanation of this hardcoded hex string 24 | const hexToSign = '0x0000000000000013456e69676d612055736572204d6573736167650000000000000040'+identity.publicKey; 25 | const signature = EthCrypto.sign(worker[4], web3Utils.soliditySha3({t: 'bytes', value: hexToSign})); 26 | callback(null, { 27 | result: { 28 | workerEncryptionKey: identity.publicKey, 29 | workerSig: utils.remove0x(signature), 30 | }, id: 'ldotj6nghv7a', 31 | }); 32 | } else { 33 | callback({code: -32602, message: 'Invalid params'}); 34 | } 35 | }, 36 | deploySecretContract: function(args, callback) { 37 | if (args.preCode && args.encryptedArgs && args.encryptedFn && args.userDHKey && args.contractAddress) { 38 | callback(null, { 39 | deploySentResult: true, 40 | }); 41 | } else { 42 | callback({code: -32602, message: 'Invalid params'}); 43 | } 44 | }, 45 | sendTaskInput: function(args, callback) { 46 | if (args.taskId && args.workerAddress && args.encryptedFn && args.encryptedArgs && args.contractAddress && args.userDHKey) { 47 | callback(null, { 48 | sendTaskResult: true, 49 | }); 50 | } else { 51 | callback({code: -32602, message: 'Invalid params'}); 52 | } 53 | }, 54 | getTaskStatus: function(args, callback) { 55 | if (args.taskId && args.workerAddress) { 56 | _counter++; 57 | let status = (_counter < 5) ? 'INPROGRESS' : 'SUCCESS'; 58 | callback(null, { 59 | result: { 60 | output: '02dc75395879faa78a598e11945c1ac926e3ba591ce91f387694983bc1d2000102030405060708090a0b', 61 | status: status, 62 | }, 63 | }); 64 | } else { 65 | callback({code: -32602, message: 'Invalid params'}); 66 | } 67 | }, 68 | getTaskResult: function(args, callback) { 69 | if (args.taskId) { 70 | switch (_counter) { 71 | case (0): 72 | _counter++; 73 | callback(null, { 74 | result: { 75 | status: 'INVALIDSTATUS', 76 | }, 77 | }); 78 | break; 79 | case (1): 80 | _counter++; 81 | callback(null, { 82 | result: null 83 | }); 84 | break; 85 | case (2): 86 | _counter++; 87 | callback(null, { 88 | result: { 89 | status: 'UNVERIFIED', 90 | }, 91 | }); 92 | break; 93 | case (3): 94 | _counter++; 95 | callback(null, { 96 | result: { 97 | status: 'INPROGRESS', 98 | }, 99 | }); 100 | break; 101 | case (4): 102 | _counter++; 103 | callback(null, { 104 | result: { 105 | taskId: '0x0033105ed3302282dddd38fcc8330a6448f6ae16bbcb26209d8740e8b3d28538', 106 | status: 'FAILED', 107 | output: '02dc75395879faa78a598e11945c1ac926e3ba591ce91f387694983bc1d2000102030405060708090a0b', 108 | usedGas: 'amount-of-gas-used', 109 | signature: 'enclave-signature', 110 | }, 111 | }); 112 | break; 113 | default: 114 | _counter++; 115 | callback(null, { 116 | result: { 117 | taskId: '0x0033105ed3302282dddd38fcc8330a6448f6ae16bbcb26209d8740e8b3d28538', 118 | status: 'SUCCESS', 119 | output: '02dc75395879faa78a598e11945c1ac926e3ba591ce91f387694983bc1d2000102030405060708090a0b', 120 | delta: {'key': 0, 'data': [11, 2, 3, 5, 41, 44]}, 121 | usedGas: 'amount-of-gas-used', 122 | ethereumPayload: 'hex of payload', 123 | ethereumAddress: 'address of the payload', 124 | signature: 'enclave-signature', 125 | }, 126 | }); 127 | } 128 | } else { 129 | callback({code: -32602, message: 'Invalid params'}); 130 | } 131 | }, 132 | }, { 133 | collect: false, // don't collect params in a single argument 134 | }); 135 | } 136 | 137 | listen() { 138 | this.app.use(cors({methods: ['POST']})); 139 | this.app.use(bodyParser.json()); 140 | this.app.use(this.server.middleware()); 141 | this.serverInstance = this.app.listen(3000); 142 | } 143 | 144 | close(done) { 145 | this.serverInstance.close(done); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /enigma-js/src/emitterConstants.js: -------------------------------------------------------------------------------- 1 | export const ERROR = 'error'; 2 | export const DEPOSIT_TRANSACTION_HASH = 'depositTransactionHash'; 3 | export const DEPOSIT_CONFIRMATION = 'depositConfirmation'; 4 | export const DEPOSIT_RECEIPT = 'depositReceipt'; 5 | export const WITHDRAW_TRANSACTION_HASH = 'withdrawTransactionHash'; 6 | export const WITHDRAW_CONFIRMATION = 'withdrawConfirmation'; 7 | export const WITHDRAW_RECEIPT = 'withdrawReceipt'; 8 | export const LOGIN_TRANSACTION_HASH = 'loginTransactionHash'; 9 | export const LOGIN_CONFIRMATION = 'loginConfirmation'; 10 | export const LOGIN_RECEIPT = 'loginReceipt'; 11 | export const LOGOUT_TRANSACTION_HASH = 'logoutTransactionHash'; 12 | export const LOGOUT_CONFIRMATION = 'logoutConfirmation'; 13 | export const LOGOUT_RECEIPT = 'logoutReceipt'; 14 | 15 | export const DEPLOY_SC_ADDR_RESULT = 'deploySCAddrResult'; 16 | export const DEPLOY_SC_ETH_TRANSACTION_HASH = 'deploySCEthTransactionHash'; 17 | export const DEPLOY_SC_ETH_CONFIRMATION = 'deploySCEthConfirmation'; 18 | export const DEPLOY_SC_ETH_RECEIPT = 'deploySCEthReceipt'; 19 | export const DEPLOY_SC_ENG_RECEIPT = 'deploySCEngReceipt'; 20 | 21 | export const CREATE_TASK = 'createTask'; 22 | export const CREATE_TASK_INPUT = 'createTaskInput'; 23 | export const CREATE_TASK_RECORD_TRANSACTION_HASH = 'createTaskRecordTransactionHash'; 24 | export const CREATE_TASK_RECORD_CONFIRMATION = 'createTaskRecordConfirmation'; 25 | export const CREATE_TASK_RECORD_RECEIPT = 'createTaskRecordReceipt'; 26 | export const CREATE_TASK_RECORD = 'createTaskRecord'; 27 | 28 | export const SEND_TASK_INPUT_RESULT = 'sendTaskInputResult'; 29 | export const POLL_TASK_STATUS_RESULT = 'pollTaskStatusResult'; 30 | export const GET_TASK_RESULT_RESULT = 'getTaskResultResult'; 31 | export const DEPLOY_SECRET_CONTRACT_RESULT = 'deploySecretContractResult'; 32 | 33 | export const RETURN_FEES_FOR_TASK_RECEIPT = 'returnFeesForTaskReceipt'; 34 | export const RETURN_FEES_FOR_TASK = 'returnFeesForTask'; 35 | 36 | export const POLL_TASK_ETH_RESULT = 'pollTaskETHResult'; 37 | 38 | export const RPC_SEND_TASK_INPUT = 'sendTaskInput'; 39 | export const RPC_DEPLOY_SECRET_CONTRACT = 'deploySecretContract'; 40 | export const RPC_GET_TASK_RESULT = 'getTaskResult'; 41 | export const RPC_GET_TASK_STATUS = 'getTaskStatus'; 42 | export const GET_TASK_RESULT_SUCCESS = 'SUCCESS'; 43 | export const GET_TASK_RESULT_FAILED = 'FAILED'; 44 | export const GET_TASK_RESULT_UNVERIFIED = 'UNVERIFIED'; 45 | export const GET_TASK_RESULT_INPROGRESS = 'INPROGRESS'; 46 | 47 | export const ETH_STATUS_UNDEFINED = 0; 48 | export const ETH_STATUS_CREATED = 1; 49 | export const ETH_STATUS_VERIFIED = 2; 50 | export const ETH_STATUS_FAILED = 3; 51 | export const ETH_STATUS_FAILED_ETH = 4; 52 | export const ETH_STATUS_FAILED_RETURN = 5; 53 | -------------------------------------------------------------------------------- /enigma-js/src/index.js: -------------------------------------------------------------------------------- 1 | import 'core-js/stable'; 2 | import 'regenerator-runtime/runtime'; 3 | // window.Promise = Promise; 4 | import utils from './enigma-utils'; 5 | import Enigma from './Enigma'; 6 | import * as eeConstants from './emitterConstants'; 7 | 8 | export {Enigma, utils, eeConstants}; 9 | -------------------------------------------------------------------------------- /enigma-js/src/models/Task.js: -------------------------------------------------------------------------------- 1 | import utils from '../enigma-utils'; 2 | 3 | /** 4 | * Encapsulates the Task 5 | */ 6 | export default class Task { 7 | /** 8 | * Task wrapper for contract deployment and regular tasks. This object is iteratively built up during the task 9 | * lifecycle 10 | * 11 | * @param {string} scAddr 12 | * @param {string} encryptedFn 13 | * @param {string} encryptedAbiEncodedArgs 14 | * @param {Number} gasLimit 15 | * @param {Number} gasPx 16 | * @param {string} msgId 17 | * @param {string} userPubKey 18 | * @param {Number} firstBlockNumber 19 | * @param {string} workerAddress 20 | * @param {string} workerEncryptionKey 21 | * @param {string} sender 22 | * @param {string} userTaskSig 23 | * @param {Number} nonce 24 | * @param {string} preCode 25 | * @param {string} preCodeHash 26 | * @param {boolean} isContractDeploymentTask 27 | */ 28 | constructor(scAddr, encryptedFn, encryptedAbiEncodedArgs, gasLimit, gasPx, msgId, userPubKey, firstBlockNumber, 29 | workerAddress, workerEncryptionKey, sender, userTaskSig, nonce, preCode, preCodeHash, 30 | isContractDeploymentTask) { 31 | // Initial task attributes 32 | this.inputsHash = utils.hash([encryptedFn, encryptedAbiEncodedArgs, 33 | isContractDeploymentTask ? preCodeHash : scAddr, userPubKey]); 34 | this.scAddr = scAddr; 35 | this.encryptedFn = encryptedFn; 36 | this.encryptedAbiEncodedArgs = encryptedAbiEncodedArgs; 37 | this.gasLimit = gasLimit; 38 | this.gasPx = gasPx; 39 | this.msgId = msgId; 40 | this.userPubKey = userPubKey; 41 | this.firstBlockNumber = firstBlockNumber; 42 | this.workerAddress = workerAddress; 43 | this.workerEncryptionKey = workerEncryptionKey; 44 | this.sender = sender; 45 | this.userTaskSig = userTaskSig; 46 | this.nonce = nonce; 47 | this.preCode = preCode; 48 | this.preCodeHash = preCodeHash; 49 | this.isContractDeploymentTask = isContractDeploymentTask; 50 | 51 | // Attributes added to task when task record is created on ETH, most critically, the taskId (a unique value 52 | // for each task computed from hash(hash(encrypted function signature, encrypted ABI-encoded arguments, gas limit, 53 | // gas price, user's ETH address), user's nonce value monotonically increasing for every task deployment) 54 | this.transactionHash = ''; 55 | this.taskId = ''; 56 | this.receipt = ''; 57 | this.ethStatus = 0; 58 | this.proof = ''; 59 | this.creationBlockNumber = -1; 60 | 61 | // Attributes added to task when computation result is being polled/retrieved from the ENG network 62 | this.encryptedAbiEncodedOutputs = ''; 63 | this.delta = ''; 64 | this.usedGas = ''; 65 | this.ethereumPayload = ''; 66 | this.ethereumAddress = ''; 67 | this.workerTaskSig = ''; 68 | this.engStatus = 'null'; 69 | 70 | this.decryptedOutput = ''; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /enigma-js/test/enigma-utils.spec.js: -------------------------------------------------------------------------------- 1 | import utils from '../src/enigma-utils'; 2 | import forge from 'node-forge'; 3 | 4 | forge.options.usePureJavaScript = true; 5 | 6 | 7 | describe('enigma-utils', () => { 8 | it('test enigma-utils', () => { 9 | expect(utils.test()).toEqual('hello2'); 10 | }); 11 | 12 | it('should successfully encrypt and decrypt the same as in rust', () => { 13 | const key = '2987699a6d3a5ebd07f4caf422fad2809dcce942cd9db266ed8e2be02cf95ee9'; // SHA256('EnigmaMPC') 14 | const iv = forge.util.hexToBytes('000102030405060708090a0b'); 15 | const msg = 'This is Enigma'; 16 | const encrypted = utils.encryptMessage(key, msg, iv); 17 | 18 | expect(encrypted).toEqual( 19 | '02dc75395879faa78a598e11945c1ac926e3ba591ce91f387694983bc1d2000102030405060708090a0b', 20 | ); 21 | 22 | expect(utils.decryptMessage(key, encrypted)).toEqual('5468697320697320456e69676d61'); 23 | expect(utils.hexToAscii(utils.decryptMessage(key, encrypted))).toEqual(msg); 24 | 25 | // Corrupt a valid encrypted message by just tweaking the first byte 26 | const invalidEncryptedMsg = '12dc75395879faa78a598e11945c1ac926e3ba591ce91f387694983bc1d2000102030405060708090a0b' 27 | // Wrap the code that throws an Error in a function, 28 | // otherwise the error will not be caught and the assertion will fail 29 | function invalidDecryption() { 30 | utils.decryptMessage(key, invalidEncryptedMsg); 31 | } 32 | expect(invalidDecryption).toThrow(); 33 | 34 | }); 35 | 36 | it('should convert hex to ascii', () => { 37 | expect(utils.hexToAscii(31323334)).toEqual('1234'); 38 | expect(utils.hexToAscii('68656c6c6f')).toEqual('hello'); 39 | expect(utils.hexToAscii('0x68656c6c6f')).toEqual('hello'); 40 | expect(utils.hexToAscii('0x68656c6c6f20776f726c64')).toEqual('hello world'); 41 | expect(utils.hexToAscii('20 20 20 20 20 68 65 6c 6c 6f 20 20 20 20 20')).toEqual(' hello '); 42 | expect(utils.hexToAscii(true)).toEqual(''); 43 | expect(utils.hexToAscii([1, 2, 3, 4, 5])).toEqual(''); 44 | }) 45 | 46 | it('should generate a task input hash', () => { 47 | const encryptedFn = 'de9bc270f30e03de84aca5ea78f18321f50ca886ff522a49d525bc24f6d56cfb2dcb0b1d33b8756196de2' + 48 | '89626a442e3dffff97312'; 49 | const encryptedAbiEncodedArgs = 'c53b8caeb99cbc78e322945d8fdcc25ed2b0a7c4319a09a63e43e63e860de572ce656b3f0' + 50 | '3d9ef7763b7b97ecb8e64a625ecbd307a5a41752c0ab2f769dd0054c9dec67373a76b9a26176760c9a819e6d827a4ec052a0ba1' + 51 | 'd6afc4378c1f4111eb91d059fab824edaf198984277df767ec0db016593c73e40804fc2f92c70dda753ad1d55fbd6b4dfde0bce' + 52 | '44b9c8be4724a7cf16eb437462bb45482f175'; 53 | const scAddrOrPreCodeHash = '0x300c3473734f4fe56d4acb834359a70d47ff2511c4839524c6f078cb28151ff4'; 54 | const userPubKey = '2ea8e4cefb78efd0725ed12b23b05079a0a433cc8a656f212accf58672fee44a20cfcaa50466237273e762' + 55 | 'e49ec912be61358d5e90bff56a53a0ed42abfe27e3'; 56 | const taskInputsHash = utils.hash([encryptedFn, encryptedAbiEncodedArgs, scAddrOrPreCodeHash, 57 | userPubKey]); 58 | expect(taskInputsHash).toEqual('0x0af2a6c64065ee3eca9ed1838a12d858dc8ccb604295bf0fa23008347c22f4b5'); 59 | }); 60 | 61 | it('should derive the same key', () => { 62 | const enclavePublicKey = 'c73d872559d1468ef05204d66a75e616493e08c2e532a3dad7d7cedac6757c4e74021348e73bce08' + 63 | 'ea178a1b8cc0e3670dd3335977b5d7b294b819b26d5db934'; 64 | const clientPrivateKey = '1737611edbedec5546e1457769f900b8d7daef442d966e60949decd63f9dd86f'; 65 | expect(utils.getDerivedKey(enclavePublicKey, clientPrivateKey)).toEqual('d98eb96fa53f96192fcab5194bfbace2f' + 66 | 'aaff7e8ebfe00c4854f8c59407f6c24'); 67 | expect(utils.getDerivedKey('04'+enclavePublicKey, clientPrivateKey)).toEqual('d98eb96fa53f96192fcab5194bfb' + 68 | 'ace2faaff7e8ebfe00c4854f8c59407f6c24'); 69 | }); 70 | 71 | it('should remove 0x where present', () => { 72 | expect(utils.remove0x('0x12345')).toEqual('12345'); 73 | expect(utils.remove0x('12345')).toEqual('12345'); 74 | }); 75 | 76 | it('should compress and decompress', async () => { 77 | const testString = 'hello world' 78 | let compressed = await utils.gzip(testString) 79 | const decompressed = await utils.gunzip(compressed); 80 | expect(decompressed.toString('ascii')).toEqual(testString); 81 | }) 82 | }); 83 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/README.md: -------------------------------------------------------------------------------- 1 | # Integration Tests 2 | 3 | All tests in this folder are excluded by default in the standard test suite when you run `yarn test`, and are used instead in the [Discovery Integration Tests](https://github.com/enigmampc/discovery-integration-tests). 4 | 5 | ## Template files for tests 6 | 7 | This repository provides template files for integrationTests, which are then parsed by a [launch script](https://github.com/enigmampc/discovery-integration-tests/blob/master/enigma-contract/start_test.bash) in the Discovery Integration Tests repo that configures IP and contract addresses for each network configuration where these tests are run. The test files are renamed at the time of parsing like so: ` template.01_init.js` becomes `01_init.spec.js`. This repository is configured to ignore the resulting test files, and only tracks the templates. 8 | 9 | ## Order in which tests are run 10 | 11 | `testList.template.txt` provides a template for which tests are run, and it is used by the Continuous Integration (CI) services in the Discovery Integration Tests repository. You can override it with: 12 | ``` 13 | $ cp testList.template.txt testList.txt 14 | ``` 15 | and editing `testList.txt` to match your needs. It is a simple text file, with one test filename per line, as documented below. Keep in mind that the list is of the actual test files, not the templates. 16 | ``` 17 | 01_init.spec.js 18 | 02_deploy_calculator.spec.js 19 | 03_deploy_fail.spec.js 20 | ``` 21 | 22 | ## Manually running the tests 23 | 24 | To run these tests, execute: 25 | ``` 26 | $ ./runTests.bash 27 | ``` 28 | which will only run the tests in this folder, and will not run all the other unit tests. This command relies on `yarn test:integration` and controls the order in which the various tests are run. If you were to run `yarn test:integration` directly, the files would be run at random. 29 | 30 | It will first check if `testList.txt` exists and run the tests listed therein. If this file does not exist, it will revert to using the tests listed in `testList.template.txt`. 31 | 32 | 33 | ## Requirements 34 | 35 | For these tests to run, it is required to have a complete Discovery release of the Enigma Network deployed in a dockerized environment, and run these tests from the `client` container. See the [Discovery Integration Tests](https://github.com/enigmampc/discovery-integration-tests) repository for more details. 36 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/contractLoader.js: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv'; 2 | 3 | import EnigmaTokenContract from '../../../build/contracts/EnigmaToken'; 4 | import SampleContract from '../../../build/contracts/Sample'; 5 | 6 | dotenv.config(); 7 | 8 | var EnigmaContract = null; 9 | if (typeof process.env.SGX_MODE !== 'undefined' && process.env.SGX_MODE == 'SW') { 10 | EnigmaContract = require('../../../build/contracts/EnigmaSimulation'); 11 | } else { 12 | EnigmaContract = require('../../../build/contracts/Enigma'); 13 | } 14 | 15 | export {EnigmaContract, EnigmaTokenContract, SampleContract} -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after the first failure 9 | // bail: false, 10 | 11 | // Respect "browser" field in package.json when resolving modules 12 | // browser: false, 13 | 14 | // The directory where Jest should store its cached dependency information 15 | // cacheDirectory: "/var/folders/87/cxhtwhvj08bghpsz99tpdwth0000gn/T/jest_dx", 16 | 17 | // Automatically clear mock calls and instances between every test 18 | clearMocks: true, 19 | 20 | // Indicates whether the coverage information should be collected while executing the test 21 | // collectCoverage: false, 22 | 23 | // An array of glob patterns indicating a set of files for which coverage information should be collected 24 | // collectCoverageFrom: null, 25 | 26 | // The directory where Jest should output its coverage files 27 | // coverageDirectory: "coverage", 28 | 29 | // An array of regexp pattern strings used to skip coverage collection 30 | // coveragePathIgnorePatterns: [ 31 | // "/node_modules/" 32 | // ], 33 | 34 | // A list of reporter names that Jest uses when writing coverage reports 35 | // coverageReporters: [ 36 | // "json", 37 | // "text", 38 | // "lcov", 39 | // "clover" 40 | // ], 41 | 42 | // An object that configures minimum threshold enforcement for coverage results 43 | // coverageThreshold: null, 44 | 45 | // Make calling deprecated APIs throw helpful error messages 46 | // errorOnDeprecated: false, 47 | 48 | // Force coverage collection from ignored files usin a array of glob patterns 49 | // forceCoverageMatch: [], 50 | 51 | // A path to a module which exports an async function that is triggered once before all test suites 52 | // globalSetup: null, 53 | 54 | // A path to a module which exports an async function that is triggered once after all test suites 55 | // globalTeardown: null, 56 | 57 | // A set of global variables that need to be available in all test environments 58 | // globals: {}, 59 | 60 | // An array of directory names to be searched recursively up from the requiring module's location 61 | // moduleDirectories: [ 62 | // "node_modules" 63 | // ], 64 | 65 | // An array of file extensions your modules use 66 | // moduleFileExtensions: [ 67 | // "js", 68 | // "json", 69 | // "jsx", 70 | // "node" 71 | // ], 72 | 73 | // A map from regular expressions to module names that allow to stub out resources with a single module 74 | // moduleNameMapper: {}, 75 | 76 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 77 | // modulePathIgnorePatterns: [], 78 | 79 | // Activates notifications for test results 80 | // notify: false, 81 | 82 | // An enum that specifies notification mode. Requires { notify: true } 83 | // notifyMode: "always", 84 | 85 | // A preset that is used as a base for Jest's configuration 86 | // preset: null, 87 | 88 | // Run tests from one or more projects 89 | // projects: null, 90 | 91 | // Use this configuration option to add custom reporters to Jest 92 | // reporters: undefined, 93 | 94 | // Automatically reset mock state between every test 95 | // resetMocks: false, 96 | 97 | // Reset the module registry before running each individual test 98 | // resetModules: false, 99 | 100 | // A path to a custom resolver 101 | // resolver: null, 102 | 103 | // Automatically restore mock state between every test 104 | // restoreMocks: false, 105 | 106 | // The root directory that Jest should scan for tests and modules within 107 | rootDir: '../..', 108 | 109 | // A list of paths to directories that Jest should use to search for files in 110 | // roots: [ 111 | // "" 112 | // ], 113 | 114 | // Allows you to use a custom runner instead of Jest's default test runner 115 | // runner: "jest-runner", 116 | 117 | // The paths to modules that run some code to configure or set up the testing environment before each test 118 | setupFiles: [ 119 | "/jest.init.js" 120 | ], 121 | 122 | // The path to a module that runs some code to configure or set up the testing framework before each test 123 | // setupTestFrameworkScriptFile: null, 124 | 125 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 126 | // snapshotSerializers: [], 127 | 128 | // The test environment that will be used for testing 129 | testEnvironment: "jsdom", 130 | 131 | // Options that will be passed to the testEnvironment 132 | // testEnvironmentOptions: {}, 133 | 134 | // Adds a location field to test results 135 | // testLocationInResults: false, 136 | 137 | // The glob patterns Jest uses to detect test files 138 | testMatch: [ 139 | "**/__tests__/**/*.js?(x)", 140 | "**/?(*.)+(spec|test).js?(x)", 141 | "**/test/integrationTests/*-integration.spec.js" 142 | ], 143 | 144 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 145 | // testPathIgnorePatterns: [ 146 | // "/node_modules/" 147 | // ], 148 | 149 | // The regexp pattern Jest uses to detect test files 150 | // testRegex: "", 151 | 152 | // This option allows the use of a custom results processor 153 | // testResultsProcessor: null, 154 | 155 | // This option allows use of a custom test runner 156 | // testRunner: "jasmine2", 157 | 158 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 159 | // testURL: "http://localhost", 160 | 161 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 162 | // timers: "real", 163 | 164 | // A map from regular expressions to paths to transformers 165 | // transform: null, 166 | 167 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 168 | // transformIgnorePatterns: [ 169 | // "/node_modules/" 170 | // ], 171 | 172 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 173 | // unmockedModulePathPatterns: undefined, 174 | 175 | // Indicates whether each individual test should be reported during the run 176 | // verbose: null, 177 | 178 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 179 | // watchPathIgnorePatterns: [], 180 | 181 | // Whether to use watchman for file crawling 182 | // watchman: true, 183 | }; 184 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/runTests.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # First, we test whether this version of bash supports arrays. 4 | whotest[0]='test' || (echo 'Failure: arrays not supported in this version of bash.' && exit 2) 5 | 6 | # Get the folder where this script is located 7 | SELFDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 8 | 9 | # cd into this folder to reference files relative to it 10 | pushd $SELFDIR > /dev/null 2>&1 11 | 12 | # Load the list of tests to run. We provide a template of all the integration 13 | # tests Enigma runs in testList.template.txt, and the user can override it by 14 | # specifying testList.txt (which is not tracked in the repo). Either file 15 | # should contain the names of the testfiles to run in order, one per line. 16 | if [ -f testList.txt ]; then 17 | tests="$(cat testList.txt)" 18 | else 19 | tests="$(cat testList.template.txt)" 20 | fi 21 | 22 | # Tests will be run sequentially. If one fails, the script will exit with error 23 | for test in ${tests[@]}; do 24 | if yarn test:integration ${test}; then 25 | continue 26 | else 27 | popd > /dev/null 2>&1 28 | exit 1 29 | fi 30 | done 31 | 32 | # silently return to the folder where this script was called from 33 | popd > /dev/null 2>&1 34 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/secretContracts/calculator.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/enigma-contract/08346f20aad4ff7377a7ff1f737e9a3ab76d0c04/enigma-js/test/integrationTests/secretContracts/calculator.wasm -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/secretContracts/erc20.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/enigma-contract/08346f20aad4ff7377a7ff1f737e9a3ab76d0c04/enigma-js/test/integrationTests/secretContracts/erc20.wasm -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/secretContracts/flipcoin.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/enigma-contract/08346f20aad4ff7377a7ff1f737e9a3ab76d0c04/enigma-js/test/integrationTests/secretContracts/flipcoin.wasm -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/secretContracts/millionaire.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/enigma-contract/08346f20aad4ff7377a7ff1f737e9a3ab76d0c04/enigma-js/test/integrationTests/secretContracts/millionaire.wasm -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/secretContracts/voting.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scrtlabs/enigma-contract/08346f20aad4ff7377a7ff1f737e9a3ab76d0c04/enigma-js/test/integrationTests/secretContracts/voting.wasm -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.02_deploy_calculator.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | let scTask; 44 | let task; 45 | const homedir = os.homedir(); 46 | 47 | it('should generate and save key/pair', () => { 48 | enigma.setTaskKeyPair('cupcake'); 49 | }); 50 | 51 | it('should deploy secret contract', async () => { 52 | let scTaskFn = 'construct()'; 53 | let scTaskArgs = ''; 54 | let scTaskGasLimit = 1000000; 55 | let scTaskGasPx = utils.toGrains(1); 56 | let preCode; 57 | try { 58 | preCode = fs.readFileSync(path.resolve(__dirname,'secretContracts/calculator.wasm')); 59 | } catch(e) { 60 | console.log('Error:', e.stack); 61 | } 62 | scTask = await new Promise((resolve, reject) => { 63 | enigma.deploySecretContract(scTaskFn, scTaskArgs, scTaskGasLimit, scTaskGasPx, accounts[0], preCode) 64 | .on(eeConstants.DEPLOY_SECRET_CONTRACT_RESULT, (receipt) => resolve(receipt)) 65 | .on(eeConstants.ERROR, (error) => reject(error)); 66 | }); 67 | 68 | fs.writeFile(path.join(homedir, '.enigma', 'addr-calculator.txt'), scTask.scAddr, 'utf8', function(err) { 69 | if(err) { 70 | return console.log(err); 71 | } 72 | }); 73 | }, constants.TIMEOUT_DEPLOY); 74 | 75 | it('should get the confirmed deploy contract task', async () => { 76 | do { 77 | await sleep(1000); 78 | scTask = await enigma.getTaskRecordStatus(scTask); 79 | process.stdout.write('Waiting. Current Task Status is '+scTask.ethStatus+'\r'); 80 | } while (scTask.ethStatus != 2); 81 | expect(scTask.ethStatus).toEqual(2); 82 | process.stdout.write('Completed. Final Task Status is '+scTask.ethStatus+'\n'); 83 | }, constants.TIMEOUT_DEPLOY); 84 | 85 | it('should verify deployed contract', async () => { 86 | const result = await enigma.admin.isDeployed(scTask.scAddr); 87 | expect(result).toEqual(true); 88 | }); 89 | 90 | it('should get deployed contract bytecode hash', async () => { 91 | const result = await enigma.admin.getCodeHash(scTask.scAddr); 92 | expect(result).toBeTruthy; 93 | console.log('Deployed contract bytecode hash is: '+result); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.02_deploy_erc20.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import elliptic from 'elliptic'; 10 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 11 | import * as constants from './testConstants'; 12 | 13 | 14 | let ec = new elliptic.ec('secp256k1'); 15 | 16 | function sleep(ms) { 17 | return new Promise(resolve => setTimeout(resolve, ms)); 18 | } 19 | 20 | describe('Enigma tests', () => { 21 | let accounts; 22 | let web3; 23 | let enigma; 24 | let epochSize; 25 | it('initializes', () => { 26 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 27 | web3 = new Web3(provider); 28 | return web3.eth.getAccounts().then((result) => { 29 | accounts = result; 30 | enigma = new Enigma( 31 | web3, 32 | EnigmaContract.networks['4447'].address, 33 | EnigmaTokenContract.networks['4447'].address, 34 | 'http://localhost:3346', 35 | { 36 | gas: 4712388, 37 | gasPrice: 100000000000, 38 | from: accounts[0], 39 | }, 40 | ); 41 | enigma.admin(); 42 | expect(Enigma.version()).toEqual('0.0.1'); 43 | }); 44 | }); 45 | 46 | let scTask; 47 | let task; 48 | const homedir = os.homedir(); 49 | 50 | it('should generate and save key/pair', () => { 51 | enigma.setTaskKeyPair('cupcake'); 52 | }); 53 | 54 | it('should deploy secret contract', async () => { 55 | let scTaskFn = 'construct()'; 56 | const account_zero_private_key = '4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d'; 57 | const keyPair0 = ec.keyFromPrivate(account_zero_private_key); 58 | const addr0 = web3.utils.keccak256(new Buffer.from(keyPair0.getPublic().encode("hex").substring(2), 'hex')); 59 | 60 | // Sanity Checks 61 | expect(keyPair0.getPrivate().toString(16)).toEqual(account_zero_private_key); 62 | expect(addr0.slice(-40)).toString(utils.remove0x(accounts[0])); 63 | 64 | let scTaskArgs = [[addr0, 'bytes32'],[1000000, 'uint256']]; 65 | let scTaskGasLimit = 4000000; 66 | let scTaskGasPx = utils.toGrains(1); 67 | let preCode; 68 | try { 69 | preCode = fs.readFileSync(path.resolve(__dirname,'secretContracts/erc20.wasm')); 70 | } catch(e) { 71 | console.log('Error:', e.stack); 72 | } 73 | scTask = await new Promise((resolve, reject) => { 74 | enigma.deploySecretContract(scTaskFn, scTaskArgs, scTaskGasLimit, scTaskGasPx, accounts[0], preCode) 75 | .on(eeConstants.DEPLOY_SECRET_CONTRACT_RESULT, (receipt) => resolve(receipt)) 76 | .on(eeConstants.ERROR, (error) => reject(error)); 77 | }); 78 | 79 | fs.writeFile(path.join(homedir, '.enigma', 'addr-erc20.txt'), scTask.scAddr, 'utf8', function(err) { 80 | if(err) { 81 | return console.log(err); 82 | } 83 | }); 84 | }, constants.TIMEOUT_DEPLOY); 85 | 86 | it('should get the confirmed deploy contract task', async () => { 87 | do { 88 | await sleep(1000); 89 | scTask = await enigma.getTaskRecordStatus(scTask); 90 | process.stdout.write('Waiting. Current Task Status is '+scTask.ethStatus+'\r'); 91 | } while (scTask.ethStatus != 2); 92 | expect(scTask.ethStatus).toEqual(2); 93 | process.stdout.write('Completed. Final Task Status is '+scTask.ethStatus+'\n'); 94 | }, constants.TIMEOUT_DEPLOY); 95 | 96 | it('should verify deployed contract', async () => { 97 | const result = await enigma.admin.isDeployed(scTask.scAddr); 98 | expect(result).toEqual(true); 99 | }); 100 | 101 | it('should get deployed contract bytecode hash', async () => { 102 | const result = await enigma.admin.getCodeHash(scTask.scAddr); 103 | expect(result).toBeTruthy; 104 | console.log('Deployed contract bytecode hash is: '+result); 105 | }); 106 | }); 107 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.02_deploy_flipcoin.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | let scTask; 44 | let task; 45 | const homedir = os.homedir(); 46 | 47 | it('should generate and save key/pair', () => { 48 | enigma.setTaskKeyPair('cupcake'); 49 | }); 50 | 51 | it('should deploy secret contract', async () => { 52 | let scTaskFn = 'construct()'; 53 | let scTaskArgs = ''; 54 | let scTaskGasLimit = 1000000; 55 | let scTaskGasPx = utils.toGrains(1); 56 | let preCode; 57 | try { 58 | preCode = fs.readFileSync(path.resolve(__dirname,'secretContracts/flipcoin.wasm')); 59 | } catch(e) { 60 | console.log('Error:', e.stack); 61 | } 62 | scTask = await new Promise((resolve, reject) => { 63 | enigma.deploySecretContract(scTaskFn, scTaskArgs, scTaskGasLimit, scTaskGasPx, accounts[0], preCode) 64 | .on(eeConstants.DEPLOY_SECRET_CONTRACT_RESULT, (receipt) => resolve(receipt)) 65 | .on(eeConstants.ERROR, (error) => reject(error)); 66 | }); 67 | 68 | fs.writeFile(path.join(homedir, '.enigma', 'addr-flipcoin.txt'), scTask.scAddr, 'utf8', function(err) { 69 | if(err) { 70 | return console.log(err); 71 | } 72 | }); 73 | }, constants.TIMEOUT_DEPLOY); 74 | 75 | it('should get the confirmed deploy contract task', async () => { 76 | do { 77 | await sleep(1000); 78 | scTask = await enigma.getTaskRecordStatus(scTask); 79 | process.stdout.write('Waiting. Current Task Status is '+scTask.ethStatus+'\r'); 80 | } while (scTask.ethStatus != 2); 81 | expect(scTask.ethStatus).toEqual(2); 82 | process.stdout.write('Completed. Final Task Status is '+scTask.ethStatus+'\n'); 83 | }, constants.TIMEOUT_DEPLOY); 84 | 85 | it('should verify deployed contract', async () => { 86 | const result = await enigma.admin.isDeployed(scTask.scAddr); 87 | expect(result).toEqual(true); 88 | }); 89 | 90 | it('should get deployed contract bytecode hash', async () => { 91 | const result = await enigma.admin.getCodeHash(scTask.scAddr); 92 | expect(result).toBeTruthy; 93 | console.log('Deployed contract bytecode hash is: '+result); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.02_deploy_millionaire.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | let scTask; 44 | let task; 45 | const homedir = os.homedir(); 46 | 47 | it('should generate and save key/pair', () => { 48 | enigma.setTaskKeyPair('cupcake'); 49 | }); 50 | 51 | it('should deploy secret contract', async () => { 52 | let scTaskFn = 'construct()'; 53 | let scTaskArgs = ''; 54 | let scTaskGasLimit = 1000000; 55 | let scTaskGasPx = utils.toGrains(1); 56 | let preCode; 57 | try { 58 | preCode = fs.readFileSync(path.resolve(__dirname,'secretContracts/millionaire.wasm')); 59 | } catch(e) { 60 | console.log('Error:', e.stack); 61 | } 62 | scTask = await new Promise((resolve, reject) => { 63 | enigma.deploySecretContract(scTaskFn, scTaskArgs, scTaskGasLimit, scTaskGasPx, accounts[0], preCode) 64 | .on(eeConstants.DEPLOY_SECRET_CONTRACT_RESULT, (receipt) => resolve(receipt)) 65 | .on(eeConstants.ERROR, (error) => reject(error)); 66 | }); 67 | 68 | fs.writeFile(path.join(homedir, '.enigma', 'addr-millionaire.txt'), scTask.scAddr, 'utf8', function(err) { 69 | if(err) { 70 | return console.log(err); 71 | } 72 | }); 73 | }, constants.TIMEOUT_DEPLOY); 74 | 75 | it('should get the confirmed deploy contract task', async () => { 76 | do { 77 | await sleep(1000); 78 | scTask = await enigma.getTaskRecordStatus(scTask); 79 | process.stdout.write('Waiting. Current Task Status is '+scTask.ethStatus+'\r'); 80 | } while (scTask.ethStatus != 2); 81 | expect(scTask.ethStatus).toEqual(2); 82 | process.stdout.write('Completed. Final Task Status is '+scTask.ethStatus+'\n'); 83 | }, constants.TIMEOUT_DEPLOY); 84 | 85 | it('should verify deployed contract', async () => { 86 | const result = await enigma.admin.isDeployed(scTask.scAddr); 87 | expect(result).toEqual(true); 88 | }); 89 | 90 | it('should get deployed contract bytecode hash', async () => { 91 | const result = await enigma.admin.getCodeHash(scTask.scAddr); 92 | expect(result).toBeTruthy; 93 | console.log('Deployed contract bytecode hash is: '+result); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.02_deploy_voting.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import VotingETHContract from '../../../build/contracts/VotingETH'; 9 | import * as eeConstants from '../../src/emitterConstants'; 10 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 11 | import * as constants from './testConstants'; 12 | 13 | 14 | function sleep(ms) { 15 | return new Promise(resolve => setTimeout(resolve, ms)); 16 | } 17 | 18 | describe('Enigma tests', () => { 19 | let accounts; 20 | let web3; 21 | let enigma; 22 | let votingETHContract; 23 | let epochSize; 24 | it('initializes', () => { 25 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 26 | web3 = new Web3(provider); 27 | return web3.eth.getAccounts().then((result) => { 28 | accounts = result; 29 | enigma = new Enigma( 30 | web3, 31 | EnigmaContract.networks['4447'].address, 32 | EnigmaTokenContract.networks['4447'].address, 33 | 'http://localhost:3346', 34 | { 35 | gas: 4712388, 36 | gasPrice: 100000000000, 37 | from: accounts[0], 38 | }, 39 | ); 40 | enigma.admin(); 41 | expect(Enigma.version()).toEqual('0.0.1'); 42 | }); 43 | }); 44 | 45 | it('should generate and save key/pair', () => { 46 | enigma.setTaskKeyPair('cupcake'); 47 | }); 48 | 49 | it('initializes VotingETH contract', async () => { 50 | votingETHContract = new enigma.web3.eth.Contract(VotingETHContract['abi'], 51 | VotingETHContract.networks['4447'].address); 52 | expect(votingETHContract.options.address).toBeTruthy(); 53 | }); 54 | 55 | let scTask; 56 | let task; 57 | const homedir = os.homedir(); 58 | it('should deploy secret contract', async () => { 59 | let scTaskFn = `construct(address)`; 60 | let scTaskArgs = [ 61 | [votingETHContract.options.address, 'address'], 62 | ]; 63 | let scTaskGasLimit = 4000000; 64 | let scTaskGasPx = utils.toGrains(1); 65 | let preCode; 66 | try { 67 | preCode = fs.readFileSync(path.resolve(__dirname,'secretContracts/voting.wasm')); 68 | } catch(e) { 69 | console.log('Error:', e.stack); 70 | } 71 | scTask = await new Promise((resolve, reject) => { 72 | enigma.deploySecretContract(scTaskFn, scTaskArgs, scTaskGasLimit, scTaskGasPx, accounts[0], preCode) 73 | .on(eeConstants.DEPLOY_SECRET_CONTRACT_RESULT, (receipt) => resolve(receipt)) 74 | .on(eeConstants.ERROR, (error) => reject(error)); 75 | }); 76 | 77 | fs.writeFile(path.join(homedir, '.enigma', 'addr-voting.txt'), scTask.scAddr, 'utf8', function(err) { 78 | if(err) { 79 | return console.log(err); 80 | } 81 | }); 82 | }, constants.TIMEOUT_DEPLOY); 83 | 84 | it('should get the confirmed deploy contract task', async () => { 85 | do { 86 | await sleep(1000); 87 | scTask = await enigma.getTaskRecordStatus(scTask); 88 | process.stdout.write('Waiting. Current Task Status is '+scTask.ethStatus+'\r'); 89 | } while (scTask.ethStatus != 2); 90 | expect(scTask.ethStatus).toEqual(2); 91 | process.stdout.write('Completed. Final Task Status is '+scTask.ethStatus+'\n'); 92 | }, constants.TIMEOUT_DEPLOY); 93 | 94 | it('should verify deployed contract', async () => { 95 | const result = await enigma.admin.isDeployed(scTask.scAddr); 96 | expect(result).toEqual(true); 97 | }); 98 | 99 | it('should get deployed contract bytecode hash', async () => { 100 | const result = await enigma.admin.getCodeHash(scTask.scAddr); 101 | expect(result).toBeTruthy; 102 | console.log('Deployed contract bytecode hash is: '+result); 103 | }); 104 | }); 105 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.03_deploy_fail_bytecode.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | let scTask1; 44 | const homedir = os.homedir(); 45 | 46 | it('should generate and save key/pair', () => { 47 | enigma.setTaskKeyPair('cupcake'); 48 | }); 49 | 50 | it('should deploy faulty secret contract', async () => { 51 | let scTaskFn = 'construct()'; 52 | let scTaskArgs = ''; 53 | let scTaskGasLimit = 100; 54 | let scTaskGasPx = utils.toGrains(1); 55 | let preCode = Buffer.from('5468697369736e6f746170726f706572736563726574636f6e74726163742e456e69676d6172756c65732e', 'hex'); 56 | 57 | scTask1 = await new Promise((resolve, reject) => { 58 | enigma.deploySecretContract(scTaskFn, scTaskArgs, scTaskGasLimit, scTaskGasPx, accounts[0], preCode) 59 | .on(eeConstants.DEPLOY_SECRET_CONTRACT_RESULT, (receipt) => resolve(receipt)) 60 | .on(eeConstants.ERROR, (error) => reject(error)); 61 | }); 62 | }); 63 | 64 | it('should get the failed receipt', async () => { 65 | do { 66 | await sleep(1000); 67 | scTask1 = await enigma.getTaskRecordStatus(scTask1); 68 | process.stdout.write('Waiting. Current Task Status is '+scTask1.ethStatus+'\r'); 69 | } while (scTask1.ethStatus != 3); 70 | expect(scTask1.ethStatus).toEqual(3); 71 | process.stdout.write('Completed. Final Task Status is '+scTask1.ethStatus+'\n'); 72 | }, constants.TIMEOUT_FAILDEPLOY); 73 | 74 | it('should fail to verify deployed contract', async () => { 75 | const result = await enigma.admin.isDeployed(scTask1.scAddr); 76 | expect(result).toEqual(false); 77 | }); 78 | 79 | it('should fail to get deployed contract bytecode hash', async () => { 80 | const result = await enigma.admin.getCodeHash(scTask1.scAddr); 81 | expect(result).toBeFalsy; 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.03_deploy_fail_constructor.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | it('should generate and save key/pair', () => { 44 | enigma.setTaskKeyPair('cupcake'); 45 | }); 46 | 47 | // The following tests below currently don't fail. 48 | // This issue is tracked here: https://github.com/enigmampc/enigma-core/issues/111 49 | 50 | let scTask2; 51 | it('should deploy secret contract with wrong constructor', async () => { 52 | let scTaskFn = 'not a valid construct()'; 53 | let scTaskArgs = ''; 54 | let scTaskGasLimit = 100; 55 | let scTaskGasPx = utils.toGrains(1); 56 | let preCode; 57 | try { 58 | preCode = fs.readFileSync(path.resolve(__dirname,'secretContracts/calculator.wasm')); 59 | } catch(e) { 60 | console.log('Error:', e.stack); 61 | } 62 | 63 | scTask2 = await new Promise((resolve, reject) => { 64 | enigma.deploySecretContract(scTaskFn, scTaskArgs, scTaskGasLimit, scTaskGasPx, accounts[0], preCode) 65 | .on(eeConstants.DEPLOY_SECRET_CONTRACT_RESULT, (receipt) => resolve(receipt)) 66 | .on(eeConstants.ERROR, (error) => reject(error)); 67 | }); 68 | }); 69 | 70 | it('should get the failed receipt', async () => { 71 | do { 72 | await sleep(1000); 73 | scTask2 = await enigma.getTaskRecordStatus(scTask2); 74 | process.stdout.write('Waiting. Current Task Status is '+scTask2.ethStatus+'\r'); 75 | } while (scTask2.ethStatus != 3); 76 | expect(scTask2.ethStatus).toEqual(3); // <- it succeeds and returns 2 instead for a successful deployment 77 | process.stdout.write('Completed. Final Task Status is '+scTask2.ethStatus+'\n'); 78 | }, constants.TIMEOUT_FAILDEPLOY); 79 | 80 | it('should fail to verify deployed contract', async () => { 81 | const result = await enigma.admin.isDeployed(scTask2.scAddr); 82 | expect(result).toEqual(false); 83 | }); 84 | 85 | it('should fail to get deployed contract bytecode hash', async () => { 86 | const result = await enigma.admin.getCodeHash(scTask2.scAddr); 87 | expect(result).toBeFalsy; 88 | }); 89 | 90 | 91 | }); 92 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.03_deploy_fail_outofgas.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | let scTask3; 44 | const homedir = os.homedir(); 45 | 46 | it('should generate and save key/pair', () => { 47 | enigma.setTaskKeyPair('cupcake'); 48 | }); 49 | 50 | it('should deploy secret contract', async () => { 51 | let scTaskFn = 'construct()'; 52 | let scTaskArgs = []; 53 | let scTaskGasLimit = 1; 54 | let scTaskGasPx = utils.toGrains(1); 55 | let preCode; 56 | try { 57 | preCode = fs.readFileSync(path.resolve(__dirname,'secretContracts/calculator.wasm')); 58 | } catch(e) { 59 | console.log('Error:', e.stack); 60 | } 61 | scTask3 = await new Promise((resolve, reject) => { 62 | enigma.deploySecretContract(scTaskFn, scTaskArgs, scTaskGasLimit, scTaskGasPx, accounts[0], preCode) 63 | .on(eeConstants.DEPLOY_SECRET_CONTRACT_RESULT, (receipt) => resolve(receipt)) 64 | .on(eeConstants.ERROR, (error) => reject(error)); 65 | }); 66 | }); 67 | 68 | it('should get the failed receipt', async () => { 69 | do { 70 | await sleep(1000); 71 | scTask3 = await enigma.getTaskRecordStatus(scTask3); 72 | process.stdout.write('Waiting. Current Task Status is '+scTask3.ethStatus+'\r'); 73 | } while (scTask3.ethStatus != 3); 74 | expect(scTask3.ethStatus).toEqual(3); 75 | process.stdout.write('Completed. Final Task Status is '+scTask3.ethStatus+'\n'); 76 | }, constants.TIMEOUT_FAILDEPLOY); 77 | 78 | it('should fail to verify deployed contract', async () => { 79 | const result = await enigma.admin.isDeployed(scTask3.scAddr); 80 | expect(result).toEqual(false); 81 | }); 82 | 83 | it('should fail to get deployed contract bytecode hash', async () => { 84 | const result = await enigma.admin.getCodeHash(scTask3.scAddr); 85 | expect(result).toBeFalsy; 86 | }); 87 | 88 | }); 89 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.03_deploy_fail_parameters.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | it('should generate and save key/pair', () => { 44 | enigma.setTaskKeyPair('cupcake'); 45 | }); 46 | 47 | let scTask2; 48 | it('should deploy secret contract', async () => { 49 | let scTaskFn = 'construct()'; 50 | let scTaskArgs = ''; // Wrong parameters, expecting ETH address 51 | let scTaskGasLimit = 1000000; 52 | let scTaskGasPx = utils.toGrains(1); 53 | let preCode; 54 | try { 55 | preCode = fs.readFileSync(path.resolve(__dirname,'secretContracts/voting.wasm')); 56 | } catch(e) { 57 | console.log('Error:', e.stack); 58 | } 59 | scTask2 = await new Promise((resolve, reject) => { 60 | enigma.deploySecretContract(scTaskFn, scTaskArgs, scTaskGasLimit, scTaskGasPx, accounts[0], preCode) 61 | .on(eeConstants.DEPLOY_SECRET_CONTRACT_RESULT, (receipt) => resolve(receipt)) 62 | .on(eeConstants.ERROR, (error) => reject(error)); 63 | }); 64 | }, constants.TIMEOUT_DEPLOY); 65 | 66 | it('should get the failed receipt', async () => { 67 | do { 68 | await sleep(1000); 69 | scTask2 = await enigma.getTaskRecordStatus(scTask2); 70 | process.stdout.write('Waiting. Current Task Status is '+scTask2.ethStatus+'\r'); 71 | } while (scTask2.ethStatus != 3); 72 | expect(scTask2.ethStatus).toEqual(3); 73 | process.stdout.write('Completed. Final Task Status is '+scTask2.ethStatus+'\n'); 74 | }, constants.TIMEOUT_DEPLOY); 75 | 76 | it('should fail to verify deployed contract', async () => { 77 | const result = await enigma.admin.isDeployed(scTask2.scAddr); 78 | expect(result).toEqual(false); 79 | }); 80 | 81 | it('should fail to get deployed contract bytecode hash', async () => { 82 | const result = await enigma.admin.getCodeHash(scTask2.scAddr); 83 | expect(result).toBeFalsy; 84 | }); 85 | 86 | }); 87 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.03_deploy_fail_wrong_encryption_key.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import Task from "../../src/models/Task"; 11 | import EventEmitter from "eventemitter3"; 12 | import * as constants from './testConstants'; 13 | 14 | 15 | function sleep(ms) { 16 | return new Promise(resolve => setTimeout(resolve, ms)); 17 | } 18 | 19 | describe('Enigma tests', () => { 20 | let accounts; 21 | let web3; 22 | let enigma; 23 | let epochSize; 24 | let workerAddress; 25 | it('initializes', () => { 26 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 27 | web3 = new Web3(provider); 28 | return web3.eth.getAccounts().then((result) => { 29 | accounts = result; 30 | enigma = new Enigma( 31 | web3, 32 | EnigmaContract.networks['4447'].address, 33 | EnigmaTokenContract.networks['4447'].address, 34 | 'http://localhost:3346', 35 | { 36 | gas: 4712388, 37 | gasPrice: 100000000000, 38 | from: accounts[0], 39 | }, 40 | ); 41 | enigma.admin(); 42 | expect(Enigma.version()).toEqual('0.0.1'); 43 | }); 44 | }); 45 | 46 | it('should generate and save key/pair', () => { 47 | enigma.setTaskKeyPair('cupcake'); 48 | }); 49 | 50 | function createWrongEncryptionKeyTask(fn, args, gasLimit, gasPx, sender, scAddrOrPreCode, isContractDeploymentTask) { 51 | let emitter = new EventEmitter(); 52 | (async () => { 53 | const nonce = parseInt(await enigma.enigmaContract.methods.getUserTaskDeployments(sender).call()); 54 | const scAddr = isContractDeploymentTask ? utils.generateScAddr(sender, nonce) : scAddrOrPreCode; 55 | 56 | let preCode; 57 | let preCodeGzip; 58 | if (isContractDeploymentTask) { 59 | if (Buffer.isBuffer(scAddrOrPreCode)) { 60 | preCode = scAddrOrPreCode; 61 | // gzip the preCode 62 | preCodeGzip = await utils.gzip(preCode); 63 | } else { 64 | throw Error('PreCode expected to be a Buffer, instead got '+typeof scAddrOrPreCode); 65 | } 66 | } else { 67 | preCode = ''; 68 | preCodeGzip = ''; 69 | } 70 | 71 | const preCodeHash = isContractDeploymentTask ? 72 | enigma.web3.utils.soliditySha3({t: 'bytes', value: preCode.toString('hex')}) : ''; 73 | const argsTranspose = (args === undefined || args.length === 0) ? [[], []] : 74 | args[0].map((col, i) => args.map((row) => row[i])); 75 | const abiEncodedArgs = utils.remove0x(enigma.web3.eth.abi.encodeParameters(argsTranspose[1], argsTranspose[0])); 76 | let abiEncodedArgsArray = []; 77 | for (let n = 0; n < abiEncodedArgs.length; n += 2) { 78 | abiEncodedArgsArray.push(parseInt(abiEncodedArgs.substr(n, 2), 16)); 79 | } 80 | const blockNumber = await enigma.web3.eth.getBlockNumber(); 81 | const workerParams = await enigma.getWorkerParams(blockNumber); 82 | const firstBlockNumber = workerParams.firstBlockNumber; 83 | workerAddress = await enigma.selectWorkerGroup(scAddr, workerParams, 1)[0]; // TODO: tmp fix 1 worker 84 | workerAddress = workerAddress.toLowerCase().slice(-40); // remove leading '0x' if present 85 | const {publicKey, privateKey} = enigma.obtainTaskKeyPair(); 86 | try { 87 | const getWorkerEncryptionKeyResult = await new Promise((resolve, reject) => { 88 | enigma.client.request('getWorkerEncryptionKey', 89 | {workerAddress: workerAddress, userPubKey: publicKey}, (err, response) => { 90 | if (err) { 91 | reject(err); 92 | return; 93 | } 94 | resolve(response); 95 | }); 96 | }); 97 | const {result, id} = getWorkerEncryptionKeyResult; 98 | const {workerSig} = result; 99 | const workerEncryptionKey = 'c54ba8ead9b94f6672da002d08caa3423695ad03842537e64317890f05fa0771457175b0f92bbe22ad8914a1f04b012a3f9883d5559f2c2749e0114fe56e7000'; 100 | // Generate derived key from worker's encryption key and user's private key 101 | const derivedKey = utils.getDerivedKey(workerEncryptionKey, privateKey); 102 | // Encrypt function and ABI-encoded args 103 | const encryptedFn = utils.encryptMessage(derivedKey, fn); 104 | const encryptedAbiEncodedArgs = utils.encryptMessage(derivedKey, Buffer.from(abiEncodedArgsArray)); 105 | const msg = enigma.web3.utils.soliditySha3( 106 | {t: 'bytes', v: encryptedFn}, 107 | {t: 'bytes', v: encryptedAbiEncodedArgs}, 108 | ); 109 | const userTaskSig = await enigma.web3.eth.sign(msg, sender); 110 | emitter.emit(eeConstants.CREATE_TASK, new Task(scAddr, encryptedFn, encryptedAbiEncodedArgs, gasLimit, gasPx, 111 | id, publicKey, firstBlockNumber, workerAddress, workerEncryptionKey, sender, userTaskSig, nonce, 112 | preCodeGzip.toString('base64'), preCodeHash, isContractDeploymentTask)); 113 | } catch (err) { 114 | emitter.emit(eeConstants.ERROR, err); 115 | } 116 | })(); 117 | return emitter; 118 | } 119 | 120 | let scTask2; 121 | it('should deploy secret contract', async () => { 122 | let scTaskFn = 'construct()'; 123 | let scTaskArgs = ''; 124 | let scTaskGasLimit = 1000000; 125 | let scTaskGasPx = utils.toGrains(1); 126 | let preCode; 127 | try { 128 | preCode = fs.readFileSync(path.resolve(__dirname,'secretContracts/calculator.wasm')); 129 | } catch(e) { 130 | console.log('Error:', e.stack); 131 | } 132 | scTask2 = await new Promise((resolve, reject) => { 133 | createWrongEncryptionKeyTask(scTaskFn, scTaskArgs, scTaskGasLimit, scTaskGasPx, accounts[0], preCode, true) 134 | .on(eeConstants.CREATE_TASK, (receipt) => resolve(receipt)) 135 | .on(eeConstants.ERROR, (error) => reject(error)); 136 | }); 137 | scTask2 = await new Promise((resolve, reject) => { 138 | enigma.createTaskRecord(scTask2) 139 | .on(eeConstants.CREATE_TASK_RECORD, (result) => resolve(result)) 140 | .on(eeConstants.ERROR, (error) => reject(error)); 141 | }); 142 | await new Promise((resolve, reject) => { 143 | enigma.sendTaskInput(scTask2) 144 | .on(eeConstants.DEPLOY_SECRET_CONTRACT_RESULT, (receipt) => resolve(receipt)) 145 | .on(eeConstants.ERROR, (error) => reject(error)); 146 | }); 147 | }); 148 | 149 | it('should get the failed receipt', async () => { 150 | do { 151 | await sleep(1000); 152 | scTask2 = await enigma.getTaskRecordStatus(scTask2); 153 | process.stdout.write('Waiting. Current Task Status is '+scTask2.ethStatus+'\r'); 154 | } while (scTask2.ethStatus !== 3); 155 | expect(scTask2.ethStatus).toEqual(3); 156 | process.stdout.write('Completed. Final Task Status is '+scTask2.ethStatus+'\n'); 157 | }, constants.TIMEOUT_FAILDEPLOY); 158 | 159 | it('should fail to verify deployed contract', async () => { 160 | const result = await enigma.admin.isDeployed(scTask2.scAddr); 161 | expect(result).toEqual(false); 162 | }); 163 | 164 | it('should fail to get deployed contract bytecode hash', async () => { 165 | const result = await enigma.admin.getCodeHash(scTask2.scAddr); 166 | expect(result).toEqual('0x0000000000000000000000000000000000000000000000000000000000000000'); 167 | }); 168 | }); 169 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.03_deploy_fail_wrong_eth_address.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | it('initializes', () => { 22 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 23 | web3 = new Web3(provider); 24 | return web3.eth.getAccounts().then((result) => { 25 | accounts = result; 26 | enigma = new Enigma( 27 | web3, 28 | EnigmaContract.networks['4447'].address, 29 | EnigmaTokenContract.networks['4447'].address, 30 | 'http://localhost:3346', 31 | { 32 | gas: 4712388, 33 | gasPrice: 100000000000, 34 | from: accounts[0], 35 | }, 36 | ); 37 | enigma.admin(); 38 | expect(Enigma.version()).toEqual('0.0.1'); 39 | }); 40 | }); 41 | 42 | let scTask; 43 | let task; 44 | const homedir = os.homedir(); 45 | 46 | it('should generate and save key/pair', () => { 47 | enigma.setTaskKeyPair('cupcake'); 48 | }); 49 | 50 | it('should deploy secret contract', async () => { 51 | let scTaskFn = `construct(address)`; 52 | let scTaskArgs = [ 53 | ['0x0000000000000000000000000000000000000102', 'address'], 54 | ]; 55 | let scTaskGasLimit = 4000000; 56 | let scTaskGasPx = utils.toGrains(1); 57 | let preCode; 58 | try { 59 | preCode = fs.readFileSync(path.resolve(__dirname,'secretContracts/voting.wasm')); 60 | } catch(e) { 61 | console.log('Error:', e.stack); 62 | } 63 | scTask = await new Promise((resolve, reject) => { 64 | enigma.deploySecretContract(scTaskFn, scTaskArgs, scTaskGasLimit, scTaskGasPx, accounts[0], preCode) 65 | .on(eeConstants.DEPLOY_SECRET_CONTRACT_RESULT, (receipt) => resolve(receipt)) 66 | .on(eeConstants.ERROR, (error) => reject(error)); 67 | }); 68 | 69 | fs.writeFile(path.join(homedir, '.enigma', 'addr-voting-wrongeth.txt'), scTask.scAddr, 'utf8', function(err) { 70 | if(err) { 71 | return console.log(err); 72 | } 73 | }); 74 | }, constants.TIMEOUT_DEPLOY); 75 | 76 | it('should get the confirmed deploy contract task', async () => { 77 | do { 78 | await sleep(1000); 79 | scTask = await enigma.getTaskRecordStatus(scTask); 80 | process.stdout.write('Waiting. Current Task Status is '+scTask.ethStatus+'\r'); 81 | } while (scTask.ethStatus !== 2); 82 | expect(scTask.ethStatus).toEqual(2); 83 | process.stdout.write('Completed. Final Task Status is '+scTask.ethStatus+'\n'); 84 | }, constants.TIMEOUT_DEPLOY); 85 | 86 | it('should verify deployed contract', async () => { 87 | const result = await enigma.admin.isDeployed(scTask.scAddr); 88 | expect(result).toEqual(true); 89 | }); 90 | 91 | it('should get deployed contract bytecode hash', async () => { 92 | const result = await enigma.admin.getCodeHash(scTask.scAddr); 93 | expect(result).toBeTruthy(); 94 | console.log('Deployed contract bytecode hash is: '+result); 95 | }); 96 | }); 97 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.10_execute_calculator.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | const homedir = os.homedir(); 44 | 45 | it('should generate and save key/pair', () => { 46 | enigma.setTaskKeyPair('cupcake'); 47 | }); 48 | 49 | const calculatorAddr = fs.readFileSync(path.join(homedir, '.enigma', 'addr-calculator.txt'), 'utf-8'); 50 | let task1; 51 | it('should execute compute task', async () => { 52 | let taskFn = 'sub(uint256,uint256)'; 53 | let taskArgs = [ 54 | [76, 'uint256'], 55 | [17, 'uint256'], 56 | ]; 57 | let taskGasLimit = 100000; 58 | let taskGasPx = utils.toGrains(1); 59 | task1 = await new Promise((resolve, reject) => { 60 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], calculatorAddr) 61 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 62 | .on(eeConstants.ERROR, (error) => reject(error)); 63 | }); 64 | }); 65 | 66 | it('should get the pending task', async () => { 67 | task1 = await enigma.getTaskRecordStatus(task1); 68 | expect(task1.ethStatus).toEqual(1); 69 | }); 70 | 71 | it('should get the confirmed task', async () => { 72 | do { 73 | await sleep(1000); 74 | task1 = await enigma.getTaskRecordStatus(task1); 75 | process.stdout.write('Waiting. Current Task Status is '+task1.ethStatus+'\r'); 76 | } while (task1.ethStatus != 2); 77 | expect(task1.ethStatus).toEqual(2); 78 | process.stdout.write('Completed. Final Task Status is '+task1.ethStatus+'\n'); 79 | }, constants.TIMEOUT_COMPUTE); 80 | 81 | it('should get the result and verify the computation is correct', async () => { 82 | task1 = await new Promise((resolve, reject) => { 83 | enigma.getTaskResult(task1) 84 | .on(eeConstants.GET_TASK_RESULT_RESULT, (result) => resolve(result)) 85 | .on(eeConstants.ERROR, (error) => reject(error)); 86 | }); 87 | expect(task1.engStatus).toEqual('SUCCESS'); 88 | expect(task1.encryptedAbiEncodedOutputs).toBeTruthy(); 89 | task1 = await enigma.decryptTaskResult(task1); 90 | expect(task1.usedGas).toBeTruthy(); 91 | expect(task1.workerTaskSig).toBeTruthy(); 92 | expect(parseInt(task1.decryptedOutput, 16)).toEqual(76-17); 93 | }); 94 | 95 | let task2; 96 | it('should execute compute task', async () => { 97 | let taskFn = 'mul(uint256,uint256)'; 98 | let taskArgs = [ 99 | [76, 'uint256'], 100 | [17, 'uint256'], 101 | ]; 102 | let taskGasLimit = 100000; 103 | let taskGasPx = utils.toGrains(1); 104 | task2 = await new Promise((resolve, reject) => { 105 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], calculatorAddr) 106 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 107 | .on(eeConstants.ERROR, (error) => reject(error)); 108 | }); 109 | }); 110 | 111 | it('should get the pending task', async () => { 112 | task2 = await enigma.getTaskRecordStatus(task2); 113 | expect(task2.ethStatus).toEqual(1); 114 | }); 115 | 116 | it('should get the confirmed task', async () => { 117 | do { 118 | await sleep(1000); 119 | task2 = await enigma.getTaskRecordStatus(task2); 120 | process.stdout.write('Waiting. Current Task Status is '+task2.ethStatus+'\r'); 121 | } while (task2.ethStatus != 2); 122 | expect(task2.ethStatus).toEqual(2); 123 | process.stdout.write('Completed. Final Task Status is '+task2.ethStatus+'\n'); 124 | }, constants.TIMEOUT_COMPUTE); 125 | 126 | it('should get and validate the result', async () => { 127 | task2 = await new Promise((resolve, reject) => { 128 | enigma.getTaskResult(task2) 129 | .on(eeConstants.GET_TASK_RESULT_RESULT, (result) => resolve(result)) 130 | .on(eeConstants.ERROR, (error) => reject(error)); 131 | }); 132 | expect(task2.engStatus).toEqual('SUCCESS'); 133 | expect(task2.encryptedAbiEncodedOutputs).toBeTruthy(); 134 | task2 = await enigma.decryptTaskResult(task2); 135 | expect(task2.usedGas).toBeTruthy(); 136 | expect(task2.workerTaskSig).toBeTruthy(); 137 | expect(parseInt(task2.decryptedOutput, 16)).toEqual(76*17); 138 | }); 139 | 140 | }); 141 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.10_execute_erc20.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader' 10 | import EthCrypto from 'eth-crypto'; 11 | import BN from 'bn.js'; 12 | import elliptic from 'elliptic'; 13 | import * as constants from './testConstants'; 14 | 15 | 16 | let ec = new elliptic.ec('secp256k1'); 17 | 18 | function sleep(ms) { 19 | return new Promise(resolve => setTimeout(resolve, ms)); 20 | } 21 | 22 | describe('Enigma tests', () => { 23 | let accounts; 24 | let web3; 25 | let enigma; 26 | let epochSize; 27 | it('initializes', () => { 28 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 29 | web3 = new Web3(provider); 30 | return web3.eth.getAccounts().then((result) => { 31 | accounts = result; 32 | enigma = new Enigma( 33 | web3, 34 | EnigmaContract.networks['4447'].address, 35 | EnigmaTokenContract.networks['4447'].address, 36 | 'http://localhost:3346', 37 | { 38 | gas: 4712388, 39 | gasPrice: 100000000000, 40 | from: accounts[0], 41 | }, 42 | ); 43 | enigma.admin(); 44 | expect(Enigma.version()).toEqual('0.0.1'); 45 | }); 46 | }); 47 | 48 | const homedir = os.homedir(); 49 | 50 | it('should generate and save key/pair', () => { 51 | enigma.setTaskKeyPair('cupcake'); 52 | }); 53 | 54 | const erc20Addr = fs.readFileSync(path.join(homedir, '.enigma', 'addr-erc20.txt'), 'utf-8'); 55 | let task; 56 | it('should execute compute task', async () => { 57 | const amount = 100000; 58 | const account_zero_private_key = '4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d'; 59 | const account_one_private_key = '6cbed15c793ce57650b9877cf6fa156fbef513c4e6134f022a85b1ffdd59b2a1'; 60 | const keyPair0 = ec.keyFromPrivate(account_zero_private_key); 61 | const keyPair1 = ec.keyFromPrivate(account_one_private_key); 62 | const addr0 = web3.utils.keccak256(new Buffer.from(keyPair0.getPublic().encode("hex").substring(2), 'hex')); 63 | const addr1 = web3.utils.keccak256(new Buffer.from(keyPair1.getPublic().encode("hex").substring(2), 'hex')); 64 | 65 | // Sanity Checks 66 | expect(keyPair0.getPrivate().toString(16)).toEqual(account_zero_private_key); 67 | expect(keyPair1.getPrivate().toString(16)).toEqual(account_one_private_key); 68 | expect(addr0.slice(-40)).toString(utils.remove0x(accounts[0])); 69 | expect(addr1.slice(-40)).toString(utils.remove0x(accounts[1])); 70 | 71 | const msg = utils.hash([addr1,(new BN(amount).toString(16, 16))]); 72 | const sig = EthCrypto.sign(account_zero_private_key, msg); 73 | 74 | let taskFn = 'mint(bytes32,bytes32,uint256,bytes)'; 75 | let taskArgs = [ 76 | [addr0,'bytes32'], 77 | [addr1,'bytes32'], 78 | [amount,'uint256'], 79 | [sig, 'bytes'] 80 | ]; 81 | let taskGasLimit = 20000000; 82 | let taskGasPx = utils.toGrains(1); 83 | task = await new Promise((resolve, reject) => { 84 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], erc20Addr) 85 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 86 | .on(eeConstants.ERROR, (error) => reject(error)); 87 | }); 88 | }); 89 | 90 | it('should get the pending task', async () => { 91 | task = await enigma.getTaskRecordStatus(task); 92 | expect(task.ethStatus).toEqual(1); 93 | }); 94 | 95 | it('should get the confirmed task', async () => { 96 | do { 97 | await sleep(1000); 98 | task = await enigma.getTaskRecordStatus(task); 99 | process.stdout.write('Waiting. Current Task Status is '+task.ethStatus+'\r'); 100 | } while (task.ethStatus != 2); 101 | expect(task.ethStatus).toEqual(2); 102 | process.stdout.write('Completed. Final Task Status is '+task.ethStatus+'\n'); 103 | }, constants.TIMEOUT_COMPUTE_LONG); 104 | 105 | it('should get the result', async () => { 106 | task = await new Promise((resolve, reject) => { 107 | enigma.getTaskResult(task) 108 | .on(eeConstants.GET_TASK_RESULT_RESULT, (result) => resolve(result)) 109 | .on(eeConstants.ERROR, (error) => reject(error)); 110 | }); 111 | expect(task.engStatus).toEqual('SUCCESS'); 112 | expect(task.encryptedAbiEncodedOutputs).toBeTruthy(); 113 | expect(task.delta).toBeTruthy(); 114 | expect(task.usedGas).toBeTruthy(); 115 | expect(task.workerTaskSig).toBeTruthy(); 116 | task = await enigma.decryptTaskResult(task); 117 | expect(task.decryptedOutput).toBe(''); 118 | }); 119 | 120 | }); 121 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.10_execute_flipcoin.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | const homedir = os.homedir(); 44 | 45 | it('should generate and save key/pair', () => { 46 | enigma.setTaskKeyPair('cupcake'); 47 | }); 48 | 49 | const flipcoinAddr = fs.readFileSync(path.join(homedir, '.enigma', 'addr-flipcoin.txt'), 'utf-8'); 50 | let task; 51 | it('should execute compute task', async () => { 52 | let taskFn = 'flip()'; 53 | let taskArgs = []; 54 | let taskGasLimit = 100000; 55 | let taskGasPx = utils.toGrains(1); 56 | task = await new Promise((resolve, reject) => { 57 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], flipcoinAddr) 58 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 59 | .on(eeConstants.ERROR, (error) => reject(error)); 60 | }); 61 | }); 62 | 63 | it('should get the pending task', async () => { 64 | task = await enigma.getTaskRecordStatus(task); 65 | expect(task.ethStatus).toEqual(1); 66 | }); 67 | 68 | it('should get the confirmed task', async () => { 69 | do { 70 | await sleep(1000); 71 | task = await enigma.getTaskRecordStatus(task); 72 | process.stdout.write('Waiting. Current Task Status is '+task.ethStatus+'\r'); 73 | } while (task.ethStatus != 2); 74 | expect(task.ethStatus).toEqual(2); 75 | process.stdout.write('Completed. Final Task Status is '+task.ethStatus+'\n'); 76 | }, constants.TIMEOUT_COMPUTE); 77 | 78 | it('should get and validate the result', async () => { 79 | task = await new Promise((resolve, reject) => { 80 | enigma.getTaskResult(task) 81 | .on(eeConstants.GET_TASK_RESULT_RESULT, (result) => resolve(result)) 82 | .on(eeConstants.ERROR, (error) => reject(error)); 83 | }); 84 | expect(task.engStatus).toEqual('SUCCESS'); 85 | expect(task.encryptedAbiEncodedOutputs).toBeTruthy(); 86 | expect(task.usedGas).toBeTruthy(); 87 | expect(task.workerTaskSig).toBeTruthy(); 88 | task = await enigma.decryptTaskResult(task); 89 | const result = parseInt(task.decryptedOutput, 16); 90 | expect(result === 1 || result === 0).toBe(true); 91 | }); 92 | 93 | }); 94 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.10_execute_millionaire.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract, SampleContract} from './contractLoader' 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | const homedir = os.homedir(); 44 | 45 | it('should generate and save key/pair', () => { 46 | enigma.setTaskKeyPair('cupcake'); 47 | }); 48 | 49 | const millionaireAddr = fs.readFileSync(path.join(homedir, '.enigma', 'addr-millionaire.txt'), 'utf-8'); 50 | 51 | let task1; 52 | const addr1 = '0x0000000000000000000000000000000000000000000000000000000000000001'; 53 | const addr2 = '0x0000000000000000000000000000000000000000000000000000000000000002'; 54 | it('should execute compute task', async () => { 55 | let taskFn = 'add_millionaire(bytes32,uint256)'; 56 | let taskArgs = [ 57 | [addr1, 'bytes32'], 58 | [1000000, 'uint256'], 59 | ]; 60 | let taskGasLimit = 1000000; 61 | let taskGasPx = utils.toGrains(1); 62 | task1 = await new Promise((resolve, reject) => { 63 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], millionaireAddr) 64 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 65 | .on(eeConstants.ERROR, (error) => reject(error)); 66 | }); 67 | }); 68 | 69 | it('should get the pending task', async () => { 70 | task1 = await enigma.getTaskRecordStatus(task1); 71 | expect(task1.ethStatus).toEqual(eeConstants.ETH_STATUS_CREATED); 72 | }); 73 | 74 | it('should get the confirmed task', async () => { 75 | do { 76 | await sleep(1000); 77 | task1 = await enigma.getTaskRecordStatus(task1); 78 | process.stdout.write('Waiting. Current Task Status is '+task1.ethStatus+'\r'); 79 | } while (task1.ethStatus != eeConstants.ETH_STATUS_VERIFIED); 80 | expect(task1.ethStatus).toEqual(eeConstants.ETH_STATUS_VERIFIED); 81 | process.stdout.write('Completed. Final Task Status is '+task1.ethStatus+'\n'); 82 | }, constants.TIMEOUT_COMPUTE); 83 | 84 | let task2; 85 | it('should execute compute task', async () => { 86 | let taskFn = 'add_millionaire(bytes32,uint256)'; 87 | let taskArgs = [ 88 | [addr2, 'bytes32'], 89 | [2000000, 'uint256'], 90 | ]; 91 | let taskGasLimit = 1000000; 92 | let taskGasPx = utils.toGrains(1); 93 | task2 = await new Promise((resolve, reject) => { 94 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], millionaireAddr) 95 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 96 | .on(eeConstants.ERROR, (error) => reject(error)); 97 | }); 98 | }); 99 | 100 | it('should get the pending task', async () => { 101 | task2 = await enigma.getTaskRecordStatus(task2); 102 | expect(task2.ethStatus).toEqual(eeConstants.ETH_STATUS_CREATED); 103 | }); 104 | 105 | it('should get the confirmed task', async () => { 106 | do { 107 | await sleep(1000); 108 | task2 = await enigma.getTaskRecordStatus(task2); 109 | process.stdout.write('Waiting. Current Task Status is '+task2.ethStatus+'\r'); 110 | } while (task2.ethStatus != eeConstants.ETH_STATUS_VERIFIED); 111 | expect(task2.ethStatus).toEqual(eeConstants.ETH_STATUS_VERIFIED); 112 | process.stdout.write('Completed. Final Task Status is '+task2.ethStatus+'\n'); 113 | }, constants.TIMEOUT_COMPUTE); 114 | 115 | let task3; 116 | it('should execute compute task', async () => { 117 | let taskFn = 'compute_richest()'; 118 | let taskArgs = []; 119 | let taskGasLimit = 1000000; 120 | let taskGasPx = utils.toGrains(1); 121 | task3 = await new Promise((resolve, reject) => { 122 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], millionaireAddr) 123 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 124 | .on(eeConstants.ERROR, (error) => reject(error)); 125 | }); 126 | }); 127 | 128 | it('should get the pending task', async () => { 129 | task3 = await enigma.getTaskRecordStatus(task3); 130 | expect(task3.ethStatus).toEqual(eeConstants.ETH_STATUS_CREATED); 131 | }); 132 | 133 | it('should get the confirmed task', async () => { 134 | do { 135 | await sleep(1000); 136 | task3 = await enigma.getTaskRecordStatus(task3); 137 | process.stdout.write('Waiting. Current Task Status is '+task3.ethStatus+'\r'); 138 | } while (task3.ethStatus != eeConstants.ETH_STATUS_VERIFIED); 139 | expect(task3.ethStatus).toEqual(eeConstants.ETH_STATUS_VERIFIED); 140 | process.stdout.write('Completed. Final Task Status is '+task3.ethStatus+'\n'); 141 | }, constants.TIMEOUT_COMPUTE); 142 | 143 | it('should get and validate the result', async () => { 144 | task3 = await new Promise((resolve, reject) => { 145 | enigma.getTaskResult(task3) 146 | .on(eeConstants.GET_TASK_RESULT_RESULT, (result) => resolve(result)) 147 | .on(eeConstants.ERROR, (error) => reject(error)); 148 | }); 149 | const verifyTaskOutput = await enigma.verifyTaskOutput(task3); 150 | const verifyTaskStatus = await enigma.verifyTaskStatus(task3); 151 | expect(verifyTaskOutput).toEqual(true); 152 | expect(verifyTaskStatus).toEqual(true); 153 | expect(task3.engStatus).toEqual('SUCCESS'); 154 | expect(task3.encryptedAbiEncodedOutputs).toBeTruthy(); 155 | expect(task3.usedGas).toBeTruthy(); 156 | expect(task3.workerTaskSig).toBeTruthy(); 157 | task3 = await enigma.decryptTaskResult(task3); 158 | expect(task3.decryptedOutput).toEqual(utils.remove0x(addr2)); 159 | }); 160 | 161 | }); 162 | 163 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.20_execute_fail_nonexistent.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | it('should generate and save key/pair', () => { 44 | enigma.setTaskKeyPair('cupcake'); 45 | }); 46 | 47 | let task; 48 | it('should execute compute task', async () => { 49 | let nonExistentAddr = '0x1234567890123456789012345678901234567890123456789012345678901234' 50 | let taskFn = 'function()'; 51 | let taskArgs = ''; 52 | let taskGasLimit = 1000; 53 | let taskGasPx = utils.toGrains(1); 54 | task = await new Promise((resolve, reject) => { 55 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], nonExistentAddr) 56 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 57 | .on(eeConstants.ERROR, (error) => reject(error)); 58 | }); 59 | }); 60 | 61 | it('should get the pending task', async () => { 62 | task = await enigma.getTaskRecordStatus(task); 63 | expect(task.ethStatus).toEqual(1); 64 | }); 65 | 66 | it('should get the failed task receipt', async () => { 67 | do { 68 | await sleep(1000); 69 | task = await enigma.getTaskRecordStatus(task); 70 | process.stdout.write('Waiting. Current Task Status is '+task.ethStatus+'\r'); 71 | } while (task.ethStatus != 3); 72 | expect(task.ethStatus).toEqual(3); 73 | process.stdout.write('Completed. Final Task Status is '+task.ethStatus+'\n'); 74 | }, constants.TIMEOUT_COMPUTE); 75 | 76 | xit('should get the failed result', async () => { 77 | task = await new Promise((resolve, reject) => { 78 | enigma.getTaskResult(task) 79 | .on(eeConstants.GET_TASK_RESULT_RESULT, (result) => resolve(result)) 80 | .on(eeConstants.ERROR, (error) => reject(error)); 81 | }); 82 | expect(task.engStatus).toEqual('FAILED'); 83 | expect(task.encryptedAbiEncodedOutputs).toBeTruthy(); 84 | expect(task.usedGas).toBeTruthy(); 85 | expect(task.workerTaskSig).toBeTruthy(); 86 | }); 87 | 88 | }); 89 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.20_execute_fail_outofgas.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | const homedir = os.homedir(); 44 | 45 | it('should generate and save key/pair', () => { 46 | enigma.setTaskKeyPair('cupcake'); 47 | }); 48 | 49 | const calculatorAddr = fs.readFileSync(path.join(homedir, '.enigma', 'addr-calculator.txt'), 'utf-8'); 50 | let task; 51 | it('should execute compute task', async () => { 52 | let taskFn = 'add(uint,uint)'; 53 | let taskArgs = [ 54 | [24, 'uint256'], 55 | [67, 'uint256'], 56 | ]; 57 | let taskGasLimit = 1; 58 | let taskGasPx = utils.toGrains(1); 59 | task = await new Promise((resolve, reject) => { 60 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], calculatorAddr) 61 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 62 | .on(eeConstants.ERROR, (error) => reject(error)); 63 | }); 64 | }); 65 | 66 | it('should get the pending task', async () => { 67 | task = await enigma.getTaskRecordStatus(task); 68 | expect(task.ethStatus).toEqual(1); 69 | }); 70 | 71 | it('should get the failed task receipt', async () => { 72 | do { 73 | await sleep(1000); 74 | task = await enigma.getTaskRecordStatus(task); 75 | process.stdout.write('Waiting. Current Task Status is '+task.ethStatus+'\r'); 76 | } while (task.ethStatus != 3); 77 | expect(task.ethStatus).toEqual(3); 78 | process.stdout.write('Completed. Final Task Status is '+task.ethStatus+'\n'); 79 | }, constants.TIMEOUT_COMPUTE); 80 | 81 | it('should get the failed result', async () => { 82 | do { 83 | await sleep(1000); 84 | task = await new Promise((resolve, reject) => { 85 | enigma.getTaskResult(task) 86 | .on(eeConstants.GET_TASK_RESULT_RESULT, (result) => resolve(result)) 87 | .on(eeConstants.ERROR, (error) => reject(error)); 88 | }); 89 | } while(!task.engStatus); 90 | expect(task.engStatus).toEqual('FAILED'); 91 | expect(task.encryptedAbiEncodedOutputs).toBeTruthy(); 92 | expect(task.workerTaskSig).toBeTruthy(); 93 | task = await enigma.decryptTaskResult(task); 94 | console.log('Output is: ' + task.decryptedOutput); 95 | }); 96 | 97 | }); 98 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.20_execute_fail_parameters.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)); 15 | } 16 | 17 | describe('Enigma tests', () => { 18 | let accounts; 19 | let web3; 20 | let enigma; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | const homedir = os.homedir(); 44 | 45 | it('should generate and save key/pair', () => { 46 | enigma.setTaskKeyPair('cupcake'); 47 | }); 48 | 49 | const calculatorAddr = fs.readFileSync(path.join(homedir, '.enigma', 'addr-calculator.txt'), 'utf-8'); 50 | let task; 51 | it('should execute compute task', async () => { 52 | let taskFn = 'add(uint,uint)'; 53 | let taskArgs = [[24, 'uint256']]; 54 | let taskGasLimit = 1000000; 55 | let taskGasPx = utils.toGrains(1); 56 | task = await new Promise((resolve, reject) => { 57 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], calculatorAddr) 58 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 59 | .on(eeConstants.ERROR, (error) => reject(error)); 60 | }); 61 | }); 62 | 63 | it('should get the pending task', async () => { 64 | task = await enigma.getTaskRecordStatus(task); 65 | expect(task.ethStatus).toEqual(1); 66 | }); 67 | 68 | it('should get the failed task receipt', async () => { 69 | do { 70 | await sleep(1000); 71 | task = await enigma.getTaskRecordStatus(task); 72 | process.stdout.write('Waiting. Current Task Status is '+task.ethStatus+'\r'); 73 | } while (task.ethStatus != 3); 74 | expect(task.ethStatus).toEqual(3); 75 | process.stdout.write('Completed. Final Task Status is '+task.ethStatus+'\n'); 76 | }, constants.TIMEOUT_COMPUTE); 77 | 78 | it('should get the failed result', async () => { 79 | task = await new Promise((resolve, reject) => { 80 | enigma.getTaskResult(task) 81 | .on(eeConstants.GET_TASK_RESULT_RESULT, (result) => resolve(result)) 82 | .on(eeConstants.ERROR, (error) => reject(error)); 83 | }); 84 | expect(task.engStatus).toEqual('FAILED'); 85 | expect(task.encryptedAbiEncodedOutputs).toBeTruthy(); 86 | expect(task.usedGas).toBeTruthy(); 87 | expect(task.workerTaskSig).toBeTruthy(); 88 | task = await enigma.decryptTaskResult(task); 89 | console.log('Output is: '+task.decryptedOutput); 90 | }); 91 | 92 | }); 93 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.20_execute_fail_wrong_encryption_key.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import EventEmitter from "eventemitter3"; 11 | import Task from "../../src/models/Task"; 12 | import * as constants from './testConstants'; 13 | 14 | 15 | function sleep(ms) { 16 | return new Promise(resolve => setTimeout(resolve, ms)); 17 | } 18 | 19 | describe('Enigma tests', () => { 20 | let accounts; 21 | let web3; 22 | let enigma; 23 | let epochSize; 24 | let workerAddress; 25 | it('initializes', () => { 26 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 27 | web3 = new Web3(provider); 28 | return web3.eth.getAccounts().then((result) => { 29 | accounts = result; 30 | enigma = new Enigma( 31 | web3, 32 | EnigmaContract.networks['4447'].address, 33 | EnigmaTokenContract.networks['4447'].address, 34 | 'http://localhost:3346', 35 | { 36 | gas: 4712388, 37 | gasPrice: 100000000000, 38 | from: accounts[0], 39 | }, 40 | ); 41 | enigma.admin(); 42 | expect(Enigma.version()).toEqual('0.0.1'); 43 | }); 44 | }); 45 | 46 | it('should generate and save key/pair', () => { 47 | enigma.setTaskKeyPair('cupcake'); 48 | }); 49 | 50 | function createWrongEncryptionKeyTask(fn, args, gasLimit, gasPx, sender, scAddrOrPreCode, isContractDeploymentTask) { 51 | let emitter = new EventEmitter(); 52 | (async () => { 53 | const nonce = parseInt(await enigma.enigmaContract.methods.getUserTaskDeployments(sender).call()); 54 | const scAddr = isContractDeploymentTask ? utils.generateScAddr(sender, nonce) : scAddrOrPreCode; 55 | const preCode = isContractDeploymentTask ? scAddrOrPreCode : ''; 56 | 57 | let preCodeArray = []; 58 | for (let n = 0; n < preCode.length; n += 2) { 59 | preCodeArray.push(parseInt(preCode.substr(n, 2), 16)); 60 | } 61 | 62 | const preCodeHash = isContractDeploymentTask ? 63 | enigma.web3.utils.soliditySha3({t: 'bytes', value: scAddrOrPreCode}) : ''; 64 | const argsTranspose = (args === undefined || args.length === 0) ? [[], []] : 65 | args[0].map((col, i) => args.map((row) => row[i])); 66 | const abiEncodedArgs = utils.remove0x(enigma.web3.eth.abi.encodeParameters(argsTranspose[1], argsTranspose[0])); 67 | let abiEncodedArgsArray = []; 68 | for (let n = 0; n < abiEncodedArgs.length; n += 2) { 69 | abiEncodedArgsArray.push(parseInt(abiEncodedArgs.substr(n, 2), 16)); 70 | } 71 | const blockNumber = await enigma.web3.eth.getBlockNumber(); 72 | const workerParams = await enigma.getWorkerParams(blockNumber); 73 | const firstBlockNumber = workerParams.firstBlockNumber; 74 | workerAddress = await enigma.selectWorkerGroup(scAddr, workerParams, 1)[0]; // TODO: tmp fix 1 worker 75 | workerAddress = workerAddress.toLowerCase().slice(-40); // remove leading '0x' if present 76 | const {publicKey, privateKey} = enigma.obtainTaskKeyPair(); 77 | try { 78 | const getWorkerEncryptionKeyResult = await new Promise((resolve, reject) => { 79 | enigma.client.request('getWorkerEncryptionKey', 80 | {workerAddress: workerAddress, userPubKey: publicKey}, (err, response) => { 81 | if (err) { 82 | reject(err); 83 | return; 84 | } 85 | resolve(response); 86 | }); 87 | }); 88 | const {result, id} = getWorkerEncryptionKeyResult; 89 | const {workerSig} = result; 90 | const workerEncryptionKey = 'c54ba8ead9b94f6672da002d08caa3423695ad03842537e64317890f05fa0771457175b0f92bbe22ad8914a1f04b012a3f9883d5559f2c2749e0114fe56e7000'; 91 | // Generate derived key from worker's encryption key and user's private key 92 | const derivedKey = utils.getDerivedKey(workerEncryptionKey, privateKey); 93 | // Encrypt function and ABI-encoded args 94 | const encryptedFn = utils.encryptMessage(derivedKey, fn); 95 | const encryptedAbiEncodedArgs = utils.encryptMessage(derivedKey, Buffer.from(abiEncodedArgsArray)); 96 | const msg = enigma.web3.utils.soliditySha3( 97 | {t: 'bytes', v: encryptedFn}, 98 | {t: 'bytes', v: encryptedAbiEncodedArgs}, 99 | ); 100 | const userTaskSig = await enigma.web3.eth.sign(msg, sender); 101 | emitter.emit(eeConstants.CREATE_TASK, new Task(scAddr, encryptedFn, encryptedAbiEncodedArgs, gasLimit, gasPx, 102 | id, publicKey, firstBlockNumber, workerAddress, workerEncryptionKey, sender, userTaskSig, nonce, 103 | preCodeArray, preCodeHash, isContractDeploymentTask)); 104 | } catch (err) { 105 | emitter.emit(eeConstants.ERROR, err); 106 | } 107 | })(); 108 | return emitter; 109 | } 110 | 111 | const homedir = os.homedir(); 112 | const calculatorAddr = fs.readFileSync(path.join(homedir, '.enigma', 'addr-calculator.txt'), 'utf-8'); 113 | let task; 114 | it('should execute compute task', async () => { 115 | let taskFn = 'sub(uint256,uint256)'; 116 | let taskArgs = [ 117 | [76, 'uint256'], 118 | [17, 'uint256'], 119 | ]; 120 | let taskGasLimit = 100000; 121 | let taskGasPx = utils.toGrains(1); 122 | 123 | task = await new Promise((resolve, reject) => { 124 | createWrongEncryptionKeyTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], calculatorAddr, false) 125 | .on(eeConstants.CREATE_TASK, (result) => resolve(result)) 126 | .on(eeConstants.ERROR, (error) => reject(error)); 127 | }); 128 | task = await new Promise((resolve, reject) => { 129 | enigma.createTaskRecord(task) 130 | .on(eeConstants.CREATE_TASK_RECORD, (result) => resolve(result)) 131 | .on(eeConstants.ERROR, (error) => reject(error)); 132 | }); 133 | await new Promise((resolve, reject) => { 134 | enigma.sendTaskInput(task) 135 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (receipt) => resolve(receipt)) 136 | .on(eeConstants.ERROR, (error) => reject(error)); 137 | }); 138 | }); 139 | 140 | it('should get the pending task', async () => { 141 | task = await enigma.getTaskRecordStatus(task); 142 | expect(task.ethStatus).toEqual(1); 143 | }); 144 | 145 | it('should get the failed task receipt', async () => { 146 | do { 147 | await sleep(1000); 148 | task = await enigma.getTaskRecordStatus(task); 149 | process.stdout.write('Waiting. Current Task Status is '+task.ethStatus+'\r'); 150 | } while (task.ethStatus !== 3); 151 | expect(task.ethStatus).toEqual(3); 152 | process.stdout.write('Completed. Final Task Status is '+task.ethStatus+'\n'); 153 | }, constants.TIMEOUT_COMPUTE); 154 | 155 | it('should get the failed result', async () => { 156 | task = await new Promise((resolve, reject) => { 157 | enigma.getTaskResult(task) 158 | .on(eeConstants.GET_TASK_RESULT_RESULT, (result) => resolve(result)) 159 | .on(eeConstants.ERROR, (error) => reject(error)); 160 | }); 161 | expect(task.engStatus).toEqual('FAILED'); 162 | expect(task.encryptedAbiEncodedOutputs).toBeTruthy(); 163 | expect(task.workerTaskSig).toBeTruthy(); 164 | }); 165 | 166 | }); 167 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.20_execute_fail_wrong_eth_address.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader'; 10 | import VotingETHContract from '../../../build/contracts/VotingETH'; 11 | import * as constants from './testConstants'; 12 | 13 | 14 | /** 15 | * Be sure to run this after 03_deploy_fail_wrong_eth_address.spec 16 | */ 17 | 18 | function sleep(ms) { 19 | return new Promise(resolve => setTimeout(resolve, ms)); 20 | } 21 | 22 | describe('Enigma tests', () => { 23 | let accounts; 24 | let web3; 25 | let enigma; 26 | let votingETHContract; 27 | it('initializes', () => { 28 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 29 | web3 = new Web3(provider); 30 | return web3.eth.getAccounts().then((result) => { 31 | accounts = result; 32 | enigma = new Enigma( 33 | web3, 34 | EnigmaContract.networks['4447'].address, 35 | EnigmaTokenContract.networks['4447'].address, 36 | 'http://localhost:3346', 37 | { 38 | gas: 4712388, 39 | gasPrice: 100000000000, 40 | from: accounts[0], 41 | }, 42 | ); 43 | enigma.admin(); 44 | expect(Enigma.version()).toEqual('0.0.1'); 45 | }); 46 | }); 47 | 48 | it('should generate and save key/pair', () => { 49 | enigma.setTaskKeyPair('cupcake'); 50 | }); 51 | 52 | it('initializes VotingETH contract', async () => { 53 | votingETHContract = new enigma.web3.eth.Contract(VotingETHContract['abi'], 54 | VotingETHContract.networks['4447'].address); 55 | expect(votingETHContract.options.address).toBeTruthy(); 56 | }); 57 | 58 | const homedir = os.homedir(); 59 | const votingAddr = fs.readFileSync(path.join(homedir, '.enigma', 'addr-voting-wrongeth.txt'), 'utf-8'); 60 | 61 | let task1; 62 | const addr1 = '0x0000000000000000000000000000000000000000000000000000000000000001'; 63 | it('should fail to execute compute task: voter 1 casting vote', async () => { 64 | const pollId = (await votingETHContract.methods.getPolls().call()).length - 1; 65 | let taskFn = 'cast_vote(uint256,bytes32,uint256)'; 66 | let taskArgs = [ 67 | [pollId, 'uint256'], 68 | [addr1, 'bytes32'], 69 | [1, 'uint256'], 70 | ]; 71 | let taskGasLimit = 1000000; 72 | let taskGasPx = utils.toGrains(1); 73 | task1 = await new Promise((resolve, reject) => { 74 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], votingAddr) 75 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 76 | .on(eeConstants.ERROR, (error) => reject(error)); 77 | }); 78 | }); 79 | 80 | it('should get the pending task', async () => { 81 | task1 = await enigma.getTaskRecordStatus(task1); 82 | expect(task1.ethStatus).toEqual(1); 83 | }); 84 | 85 | it('should get the confirmed task failure (ENG)', async () => { 86 | do { 87 | await sleep(1000); 88 | task1 = await enigma.getTaskRecordStatus(task1); 89 | process.stdout.write('Waiting. Current Task Status is '+task1.ethStatus+'\r'); 90 | } while (task1.ethStatus !== 3); 91 | expect(task1.ethStatus).toEqual(3); 92 | process.stdout.write('Completed. Final Task Status is '+task1.ethStatus+'\n'); 93 | }, constants.TIMEOUT_COMPUTE_LONG); 94 | }); 95 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.20_execute_fail_wrong_eth_payload.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract} from './contractLoader' 10 | import VotingETHContract from '../../../build/contracts/VotingETH'; 11 | import * as constants from './testConstants'; 12 | 13 | 14 | /** 15 | * Be sure to run this after 02_deploy_voting.spec 16 | */ 17 | 18 | function sleep(ms) { 19 | return new Promise(resolve => setTimeout(resolve, ms)); 20 | } 21 | 22 | describe('Enigma tests', () => { 23 | let accounts; 24 | let web3; 25 | let enigma; 26 | let votingETHContract; 27 | let epochSize; 28 | it('initializes', () => { 29 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 30 | web3 = new Web3(provider); 31 | return web3.eth.getAccounts().then((result) => { 32 | accounts = result; 33 | enigma = new Enigma( 34 | web3, 35 | EnigmaContract.networks['4447'].address, 36 | EnigmaTokenContract.networks['4447'].address, 37 | 'http://localhost:3346', 38 | { 39 | gas: 4712388, 40 | gasPrice: 100000000000, 41 | from: accounts[0], 42 | }, 43 | ); 44 | enigma.admin(); 45 | expect(Enigma.version()).toEqual('0.0.1'); 46 | }); 47 | }); 48 | 49 | it('should generate and save key/pair', () => { 50 | enigma.setTaskKeyPair('cupcake'); 51 | }); 52 | 53 | it('initializes VotingETH contract', async () => { 54 | votingETHContract = new enigma.web3.eth.Contract(VotingETHContract['abi'], 55 | VotingETHContract.networks['4447'].address); 56 | expect(votingETHContract.options.address).toBeTruthy(); 57 | }); 58 | 59 | const homedir = os.homedir(); 60 | const votingAddr = fs.readFileSync(path.join(homedir, '.enigma', 'addr-voting.txt'), 'utf-8'); 61 | 62 | let task1; 63 | const addr1 = '0x0000000000000000000000000000000000000000000000000000000000000001'; 64 | it('should fail to execute compute task: voter 1 casting vote', async () => { 65 | const pollId = (await votingETHContract.methods.getPolls().call()).length - 1; 66 | // there is no function signature cast_vote_bad, should be cast_vote, thus this is an incorrect payload 67 | let taskFn = 'cast_vote_bad(uint256,bytes32,uint256)'; 68 | let taskArgs = [ 69 | [pollId, 'uint256'], 70 | [addr1, 'bytes32'], 71 | [1, 'uint256'], 72 | ]; 73 | let taskGasLimit = 1000000; 74 | let taskGasPx = utils.toGrains(1); 75 | task1 = await new Promise((resolve, reject) => { 76 | enigma.computeTask(taskFn, taskArgs, taskGasLimit, taskGasPx, accounts[0], votingAddr) 77 | .on(eeConstants.SEND_TASK_INPUT_RESULT, (result) => resolve(result)) 78 | .on(eeConstants.ERROR, (error) => reject(error)); 79 | }); 80 | }); 81 | 82 | it('should get the pending task', async () => { 83 | task1 = await enigma.getTaskRecordStatus(task1); 84 | expect(task1.ethStatus).toEqual(1); 85 | }); 86 | 87 | it('should get the confirmed task failure (ENG)', async () => { 88 | do { 89 | await sleep(1000); 90 | task1 = await enigma.getTaskRecordStatus(task1); 91 | process.stdout.write('Waiting. Current Task Status is '+task1.ethStatus+'\r'); 92 | } while (task1.ethStatus !== 3); 93 | expect(task1.ethStatus).toEqual(3); 94 | process.stdout.write('Completed. Final Task Status is '+task1.ethStatus+'\n'); 95 | }, constants.TIMEOUT_COMPUTE_LONG); 96 | }); 97 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.90_advance_epoch.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import os from 'os'; 4 | import path from 'path'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import * as eeConstants from '../../src/emitterConstants'; 8 | import {EnigmaContract, EnigmaTokenContract, SampleContract} from './contractLoader'; 9 | import * as constants from './testConstants'; 10 | 11 | 12 | function sleep(ms) { 13 | return new Promise(resolve => setTimeout(resolve, ms)); 14 | } 15 | 16 | describe('Init tests', () => { 17 | let accounts; 18 | let web3; 19 | let enigma; 20 | let sampleContract; 21 | let epochSize; 22 | it('initializes', () => { 23 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 24 | web3 = new Web3(provider); 25 | return web3.eth.getAccounts().then((result) => { 26 | accounts = result; 27 | enigma = new Enigma( 28 | web3, 29 | EnigmaContract.networks['4447'].address, 30 | EnigmaTokenContract.networks['4447'].address, 31 | 'http://localhost:3346', 32 | { 33 | gas: 4712388, 34 | gasPrice: 100000000000, 35 | from: accounts[0], 36 | }, 37 | ); 38 | enigma.admin(); 39 | expect(Enigma.version()).toEqual('0.0.1'); 40 | }); 41 | }); 42 | 43 | it('should move forward to the beginning of next epoch by calling dummy contract', async () => { 44 | const homedir = os.homedir(); 45 | const sampleAddr = fs.readFileSync(path.join(homedir, '.enigma', 'addr-sample.txt'), 'utf-8'); 46 | const sampleContract = new enigma.web3.eth.Contract(SampleContract['abi'], sampleAddr); 47 | const currentBlock = await enigma.web3.eth.getBlockNumber(); 48 | const firstBlock = parseInt(await enigma.enigmaContract.methods.getFirstBlockNumber(currentBlock).call()); 49 | const epochSize = parseInt(await enigma.enigmaContract.methods.getEpochSize().call()); 50 | const epochRemains = (firstBlock + epochSize) - currentBlock; 51 | for (let i = 0; i < epochRemains; i++) { 52 | await sampleContract.methods.incrementCounter().send({from: accounts[8]}); 53 | } 54 | // Wait for 2s for the Ppal node to pick up the new epoch 55 | await sleep(3000); 56 | }, constants.TIMEOUT_ADVANCE); 57 | 58 | }); 59 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/template.99_cleanup.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable require-jsdoc */ 2 | import fs from 'fs'; 3 | import path from 'path'; 4 | import dotenv from 'dotenv'; 5 | import Web3 from 'web3'; 6 | import Enigma from '../../src/Enigma'; 7 | import utils from '../../src/enigma-utils'; 8 | import * as eeConstants from '../../src/emitterConstants'; 9 | import {EnigmaContract, EnigmaTokenContract, SampleContract} from './contractLoader'; 10 | import * as constants from './testConstants'; 11 | 12 | dotenv.config(); 13 | 14 | function sleep(ms) { 15 | return new Promise(resolve => setTimeout(resolve, ms)); 16 | } 17 | 18 | describe('Enigma tests', () => { 19 | let accounts; 20 | let web3; 21 | let enigma; 22 | let epochSize; 23 | let sampleContract; 24 | 25 | let nodes = parseInt((typeof process.env.NODES !== 'undefined') ? process.env.NODES : 1); 26 | 27 | it('initializes', () => { 28 | const provider = new Web3.providers.HttpProvider('http://localhost:9545'); 29 | web3 = new Web3(provider); 30 | return web3.eth.getAccounts().then((result) => { 31 | accounts = result; 32 | enigma = new Enigma( 33 | web3, 34 | EnigmaContract.networks['4447'].address, 35 | EnigmaTokenContract.networks['4447'].address, 36 | 'http://localhost:3346', 37 | { 38 | gas: 4712388, 39 | gasPrice: 100000000000, 40 | from: accounts[0], 41 | }, 42 | ); 43 | enigma.admin(); 44 | expect(Enigma.version()).toEqual('0.0.1'); 45 | }); 46 | }); 47 | 48 | it('initializes Sample contract', async () => { 49 | sampleContract = new enigma.web3.eth.Contract(SampleContract['abi'], 50 | SampleContract.networks['4447'].address); 51 | expect(sampleContract.options.address).toBeTruthy; 52 | }); 53 | 54 | it('should clean up', async() => { 55 | // Log out 56 | let promises = []; 57 | for (let i = 0; i < nodes; i++) { 58 | let promise = new Promise((resolve, reject) => { 59 | enigma.admin.logout(accounts[i]) 60 | .on(eeConstants.LOGOUT_RECEIPT, (result) => { 61 | resolve(result); 62 | }) 63 | .on(eeConstants.ERROR, (err) => { 64 | reject(err); 65 | }); 66 | }); 67 | promises.push(promise); 68 | } 69 | const logoutReceipts = await Promise.all(promises); 70 | expect(logoutReceipts.length).toEqual(nodes); 71 | 72 | let workerStatuses = [] 73 | let resultsArray = []; 74 | for(let i = 0; i < nodes; i++) { 75 | workerStatuses.push(await enigma.admin.getWorkerStatus(accounts[i])); 76 | resultsArray[i] = 2; 77 | } 78 | expect(workerStatuses).toEqual(resultsArray); 79 | 80 | // Advance epoch to be able to withdraw 81 | const epochSize = await enigma.enigmaContract.methods.getEpochSize().call(); 82 | for (let i = 0; i < epochSize; i++) { 83 | await sampleContract.methods.incrementCounter().send({from: accounts[8]}); 84 | } 85 | 86 | // Wait for 2s for the Ppal node to pick up the new epoch 87 | await sleep(2000); 88 | 89 | // Withdraw stake 90 | promises = []; 91 | for (let i = 0; i < nodes; i++) { 92 | let bal = parseInt((await enigma.enigmaContract.methods.getWorker(accounts[i]).call()).balance); 93 | let promise = new Promise((resolve, reject) => { 94 | enigma.admin.withdraw(accounts[i], bal). 95 | on(eeConstants.WITHDRAW_RECEIPT, (result) => resolve(result)). 96 | on(eeConstants.ERROR, (err) => { 97 | reject(err); 98 | }); 99 | }); 100 | promises.push(promise); 101 | } 102 | const results = await Promise.all(promises); 103 | expect(results.length).toEqual(nodes); 104 | 105 | // Check balances are zero 106 | let endingBalances = []; 107 | resultsArray = []; 108 | for (let i = 0; i < nodes; i++) { 109 | endingBalances[i] = parseInt((await enigma.enigmaContract.methods.getWorker(accounts[i]).call()).balance); 110 | resultsArray[i] = 0; 111 | } 112 | expect(endingBalances).toEqual(resultsArray); 113 | }, constants.TIMEOUT_CLEANUP); 114 | 115 | }); 116 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/testConstants.js: -------------------------------------------------------------------------------- 1 | export const TIMEOUT_LOGIN=20000; 2 | export const TIMEOUT_DEPLOY=50000; 3 | export const TIMEOUT_COMPUTE=30000; 4 | export const TIMEOUT_COMPUTE_LONG=50000; 5 | export const TIMEOUT_FAILDEPLOY=25000; 6 | export const TIMEOUT_ADVANCE=10000; 7 | export const TIMEOUT_CLEANUP=20000; 8 | export const TIMEOUT_INIT=10000; 9 | -------------------------------------------------------------------------------- /enigma-js/test/integrationTests/testList.template.txt: -------------------------------------------------------------------------------- 1 | 01_init.spec.js 2 | 02_deploy_calculator.spec.js 3 | 02_deploy_flipcoin.spec.js 4 | 02_deploy_millionaire.spec.js 5 | 02_deploy_voting.spec.js 6 | 02_deploy_erc20.spec.js 7 | 03_deploy_fail_bytecode.spec.js 8 | 03_deploy_fail_outofgas.spec.js 9 | 03_deploy_fail_parameters.spec.js 10 | 03_deploy_fail_wrong_encryption_key.spec.js 11 | 03_deploy_fail_wrong_eth_address.spec.js 12 | 10_execute_calculator.spec.js 13 | 10_execute_flipcoin.spec.js 14 | 10_execute_millionaire.spec.js 15 | 10_execute_voting.spec.js 16 | 10_execute_erc20.spec.js 17 | 20_execute_fail_outofgas.spec.js 18 | 20_execute_fail_parameters.spec.js 19 | 20_execute_fail_wrong_encryption_key.spec.js 20 | -------------------------------------------------------------------------------- /enigma-js/test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require jsdom-global/register --require @babel/register 2 | -------------------------------------------------------------------------------- /enigma-js/test/principal-utils.js: -------------------------------------------------------------------------------- 1 | import Docker from 'dockerode'; 2 | import web3Utils from 'web3-utils'; 3 | import msgpack from 'msgpack-lite'; 4 | import EthCrypto from 'eth-crypto'; 5 | import utils from '../src/enigma-utils'; 6 | 7 | const docker = new Docker(); 8 | exports.execInContainer = (enigma, commandOption, resetEpochState = false) => { 9 | let container = docker.getContainer(process.env.PRINCIPAL_CONTAINER); 10 | return new Promise((resolve, reject) => { 11 | const contractAddress = enigma.enigmaContract.options.address.substring(2); 12 | const epochStateOption = (resetEpochState) ? '-s' : ''; 13 | const cmd = ['bash', '-c', `./enigma-principal-app ${commandOption} ${epochStateOption} -c ${contractAddress}`]; 14 | const cmdStr = cmd.join(' '); 15 | console.log('Calling:\n', cmdStr); 16 | container.exec( 17 | { 18 | Cmd: cmd, 19 | AttachStdin: true, 20 | AttachStdout: true, 21 | WorkingDir: '/root/src/enigma-principal/bin', 22 | }, (err, exec) => { 23 | exec.start({hijack: true, stdin: true}, (err, stream) => { 24 | if (err) { 25 | reject(err); 26 | return; 27 | } 28 | let out = ''; 29 | stream.on('data', (line) => { 30 | out += line; 31 | }); 32 | stream.on('error', (err) => { 33 | out += err; 34 | }); 35 | stream.on('end', () => { 36 | const txFrom = out.lastIndexOf('0x'); 37 | const txLen = out.length - txFrom; 38 | console.log(`Called cmd ${cmdStr}:\n${out}`); 39 | if (txLen === 67) { 40 | const tx = out.substr(txFrom); 41 | resolve(tx); 42 | } else { 43 | reject(`Unable to call command ${commandOption} from the Principal node container: ${out}`); 44 | } 45 | }); 46 | }); 47 | }); 48 | }); 49 | }; 50 | 51 | exports.getStateKeysInContainer = (enigma, worker, scAddrs) => { 52 | let container = docker.getContainer(process.env.PRINCIPAL_CONTAINER); 53 | const identity = EthCrypto.createIdentity(); 54 | let pubkey = []; 55 | for (let n = 0; n < identity.publicKey.length; n += 2) { 56 | pubkey.push(parseInt(identity.publicKey.substr(n, 2), 16)); 57 | } 58 | const prefix = 'Enigma Message'.split('').map((c) => c.charCodeAt(0)); 59 | const request = { 60 | prefix: prefix, 61 | data: {Request: scAddrs.map((a) => web3Utils.hexToBytes(a))}, 62 | pubkey: pubkey, 63 | id: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 64 | }; 65 | console.log('The JSON request', JSON.stringify(request)); 66 | const buffer = msgpack.encode(request); 67 | const msg = buffer.toString('hex'); 68 | const signature = EthCrypto.sign(worker[4], web3Utils.soliditySha3({ 69 | t: 'bytes', 70 | value: msg, 71 | })); 72 | const params = JSON.stringify([msg, utils.remove0x(signature)]); 73 | console.log('The getStateKeys params:', params); 74 | return new Promise((resolve, reject) => { 75 | const contractAddress = enigma.enigmaContract.options.address.substring(2); 76 | const cmd = ['bash', '-c', `./enigma-principal-app -k '${params}' -c ${contractAddress}`]; 77 | const cmdStr = cmd.join(' '); 78 | console.log('Calling:\n', cmdStr); 79 | container.exec( 80 | { 81 | Cmd: cmd, 82 | AttachStdin: true, 83 | AttachStdout: true, 84 | WorkingDir: '/root/src/enigma-principal/bin', 85 | }, (err, exec) => { 86 | exec.start({hijack: true, stdin: true}, (err, stream) => { 87 | if (err) { 88 | reject(err); 89 | return; 90 | } 91 | let out = ''; 92 | stream.on('data', (line) => { 93 | out += line; 94 | }); 95 | stream.on('error', (err) => { 96 | out += err; 97 | }); 98 | stream.on('end', () => { 99 | console.log(`Called cmd ${cmdStr}:\n${out}`); 100 | const from = out.lastIndexOf('{"data"'); 101 | if (from != -1) { 102 | const response = JSON.parse(out.substr(from)); 103 | const data = msgpack.decode(response.data); 104 | console.log('Got response', response, data); 105 | resolve(response); 106 | } else { 107 | reject(`Unable to setStateKeys from the Principal node container: ${out}`); 108 | } 109 | }); 110 | }); 111 | }); 112 | }); 113 | }; 114 | -------------------------------------------------------------------------------- /enigma-js/webpack.config.js: -------------------------------------------------------------------------------- 1 | /* global __dirname, require, module*/ 2 | 3 | const path = require('path'); 4 | const webpack = require('webpack'); 5 | const nodeExternals = require('webpack-node-externals'); 6 | const CreateFileWebpack = require('create-file-webpack') 7 | const env = require('yargs').argv.env; // use --env with webpack 2 8 | const pkg = require('./package.json'); 9 | 10 | 11 | let libraryName = pkg.name; 12 | 13 | let outputFile, mode; 14 | 15 | if (env === 'build') { 16 | mode = 'production'; 17 | outputFile = libraryName + '.min.js'; 18 | outputFileNode = libraryName + '.node.min.js'; 19 | } else { 20 | mode = 'development'; 21 | outputFile = libraryName + '.js'; 22 | outputFileNode = libraryName + '.node.js'; 23 | } 24 | 25 | const config = { 26 | target: 'web', 27 | mode: mode, 28 | entry: [__dirname + '/src/index.js'], 29 | devtool: 'source-map', 30 | plugins: [ 31 | new webpack.NormalModuleReplacementPlugin(/^any-promise$/, 'bluebird'), 32 | ], 33 | output: { 34 | path: __dirname + '/lib', 35 | filename: outputFile, 36 | library: libraryName, 37 | libraryTarget: 'umd', 38 | umdNamedDefine: true, 39 | }, 40 | module: { 41 | rules: [ 42 | { 43 | test: /(\.jsx|\.js)$/, 44 | loader: 'babel-loader', 45 | exclude: /(node_modules|bower_components)/, 46 | }, 47 | { 48 | test: /(\.jsx|\.js)$/, 49 | loader: 'eslint-loader', 50 | exclude: /node_modules/, 51 | }, 52 | ], 53 | }, 54 | resolve: { 55 | modules: [path.resolve('./node_modules'), path.resolve('./src')], 56 | extensions: ['.json', '.js'], 57 | }, 58 | }; 59 | 60 | const serverConfig = { 61 | target: 'async-node', 62 | mode: mode, 63 | entry: [__dirname + '/src/index.js'], 64 | devtool: 'source-map', 65 | plugins: [ 66 | new CreateFileWebpack({ 67 | path: __dirname, 68 | fileName: 'node.js', 69 | content: `const {Enigma, utils, eeConstants} = require('./lib/${outputFileNode}');\nmodule.exports = {Enigma, utils, eeConstants};`, 70 | }) 71 | ], 72 | output: { 73 | path: __dirname + '/lib', 74 | filename: outputFileNode, 75 | library: libraryName, 76 | libraryTarget: 'umd', 77 | umdNamedDefine: true, 78 | }, 79 | module: { 80 | rules: [ 81 | { 82 | test: /(\.jsx|\.js)$/, 83 | loader: 'babel-loader', 84 | exclude: /(node_modules|bower_components)/, 85 | }, 86 | { 87 | test: /(\.jsx|\.js)$/, 88 | loader: 'eslint-loader', 89 | exclude: /node_modules/, 90 | }, 91 | ], 92 | }, 93 | externals: [nodeExternals()], 94 | } 95 | 96 | module.exports = [config, serverConfig]; 97 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | const dotenv = require('dotenv'); 2 | const EnigmaToken = artifacts.require('EnigmaToken.sol'); 3 | const SolRsaVerify = artifacts.require('./utils/SolRsaVerify.sol'); 4 | const SecretContractImpl = artifacts.require('./impl/SecretContractImpl.sol'); 5 | const Sample = artifacts.require('Sample.sol'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | const VotingETH = artifacts.require('VotingETH.sol'); 9 | 10 | const PRINCIPAL_SIGNING_ADDRESS = '0xa7595124f19a31b70a7d919ef8502ca5eb5e8225'; 11 | const EPOCH_SIZE = 10; 12 | const TIMEOUT_THRESHOLD = 2; 13 | 14 | dotenv.config(); // Reads .env configuration file, if present 15 | 16 | const Enigma = (typeof process.env.SGX_MODE !== 'undefined' && process.env.SGX_MODE == 'SW') ? 17 | artifacts.require('EnigmaSimulation.sol') : 18 | artifacts.require('Enigma.sol'); 19 | const WorkersImpl = (typeof process.env.SGX_MODE !== 'undefined' && process.env.SGX_MODE == 'SW') ? 20 | artifacts.require('./impl/WorkersImplSimulation.sol') : 21 | artifacts.require('./impl/WorkersImpl.sol'); 22 | const PrincipalImpl = (typeof process.env.SGX_MODE !== 'undefined' && process.env.SGX_MODE == 'SW') ? 23 | artifacts.require('./impl/PrincipalImplSimulation.sol') : 24 | artifacts.require('./impl/PrincipalImpl.sol'); 25 | const TaskImpl = (typeof process.env.SGX_MODE !== 'undefined' && process.env.SGX_MODE == 'SW') ? 26 | artifacts.require('./impl/TaskImplSimulation.sol') : 27 | artifacts.require('./impl/TaskImpl.sol'); 28 | 29 | async function deployProtocol(deployer) { 30 | await Promise.all([ 31 | deployer.deploy(EnigmaToken), 32 | deployer.deploy(SolRsaVerify), 33 | deployer.deploy(WorkersImpl), 34 | deployer.deploy(SecretContractImpl), 35 | ]); 36 | 37 | if (typeof process.env.SGX_MODE !== 'undefined' && process.env.SGX_MODE == 'SW') { 38 | await Promise.all([ 39 | TaskImpl.link('WorkersImplSimulation', WorkersImpl.address), 40 | PrincipalImpl.link('WorkersImplSimulation', WorkersImpl.address), 41 | ]); 42 | } else { 43 | await Promise.all([ 44 | TaskImpl.link('WorkersImpl', WorkersImpl.address), 45 | PrincipalImpl.link('WorkersImpl', WorkersImpl.address), 46 | ]); 47 | } 48 | 49 | await Promise.all([ 50 | deployer.deploy(TaskImpl), 51 | deployer.deploy(PrincipalImpl), 52 | ]); 53 | 54 | await Promise.all([ 55 | (typeof process.env.SGX_MODE !== 'undefined' && process.env.SGX_MODE == 'SW') ? 56 | Enigma.link('WorkersImplSimulation', WorkersImpl.address) : 57 | Enigma.link('WorkersImpl', WorkersImpl.address), 58 | Enigma.link('PrincipalImpl', PrincipalImpl.address), 59 | Enigma.link('TaskImpl', TaskImpl.address), 60 | Enigma.link('SecretContractImpl', SecretContractImpl.address), 61 | ]); 62 | 63 | let principal = PRINCIPAL_SIGNING_ADDRESS; 64 | const homedir = require('os').homedir(); 65 | const principalSignAddrFile = path.join(homedir, '.enigma', 'principal-sign-addr.txt'); 66 | if (fs.existsSync(principalSignAddrFile)) { 67 | principal = fs.readFileSync(principalSignAddrFile, 'utf-8'); 68 | } 69 | console.log('using account', principal, 'as principal signer'); 70 | await deployer.deploy(Enigma, EnigmaToken.address, principal, EPOCH_SIZE, TIMEOUT_THRESHOLD); 71 | await deployer.deploy(Sample); 72 | await deployer.deploy(VotingETH); 73 | 74 | if(fs.existsSync(path.join(homedir, '.enigma'))){ 75 | // Writing enigma contracts to a file for other processes to retrieve, if ~/.enigma exists 76 | fs.writeFile(path.join(homedir, '.enigma', 'enigmacontract.txt'), Enigma.address, 'utf8', function(err) { 77 | if(err) { 78 | return console.log(err); 79 | } 80 | }); 81 | fs.writeFile(path.join(homedir, '.enigma', 'enigmatokencontract.txt'), EnigmaToken.address, 'utf8', function(err) { 82 | if(err) { 83 | return console.log(err); 84 | } 85 | }); 86 | } 87 | } 88 | 89 | async function doMigration(deployer) { 90 | await deployProtocol(deployer); 91 | } 92 | 93 | module.exports = function(deployer) { 94 | deployer.then(() => doMigration(deployer)); 95 | }; 96 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "enigma-contract", 3 | "version": "0.3.0", 4 | "description": "The Solidity contracts of the Enigma Protocol with a Truffle test bed.", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/enigmampc/enigma-contract.git" 8 | }, 9 | "keywords": [], 10 | "author": "Enigma", 11 | "license": "MIT", 12 | "bugs": { 13 | "url": "https://github.com/enigmampc/enigma-contract/issues" 14 | }, 15 | "homepage": "https://enigma.co", 16 | "dependencies": { 17 | "bn.js": "^4.11.8" 18 | }, 19 | "devDependencies": { 20 | "@babel/cli": "^7.5.5", 21 | "@babel/core": "^7.5.5", 22 | "@babel/preset-env": "^7.5.5", 23 | "@babel/register": "^7.5.5", 24 | "buffer": "^5.1.0", 25 | "core-js": "^3.1.4", 26 | "dotenv": "^6.2.0", 27 | "elliptic": "6.4.0", 28 | "eth-crypto": "^1.2.2", 29 | "ethereumjs-abi": "^0.6.5", 30 | "msgpack-lite": "^0.1.26", 31 | "node-forge": "^0.7.5", 32 | "openzeppelin-solidity": "2.1", 33 | "regenerator-runtime": "^0.13.3", 34 | "rlp": "2.1.0", 35 | "truffle-contract": "^4.0.0", 36 | "web3": "1.0.0-beta.37", 37 | "web3-utils": "1.0.0-beta.37" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /scripts/checkSimulationContracts.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if script is called with the '--fix' parameter 4 | if [ "$1" == "--fix" ]; then FIX=1; else FIX=0; fi 5 | 6 | # Get the folder where the script is located 7 | SELFDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 8 | 9 | # cd into that folder to reference folders relative to it 10 | pushd $SELFDIR > /dev/null 2>&1 11 | 12 | # contracts folder relative to where this script is located 13 | CONTRACTSDIR='../contracts'; 14 | IMPLDIR="$CONTRACTSDIR/impl"; 15 | 16 | # Replace what needs to be replaced in Enigma.sol to support Simulation 17 | sed -e "s#import { WorkersImpl } from \"./impl/WorkersImpl.sol\";#import { WorkersImplSimulation } from \"./impl/WorkersImplSimulation.sol\";#" $CONTRACTSDIR/Enigma.sol > EnigmaSimulation.sol 18 | sed -e "s/contract Enigma is/contract EnigmaSimulation is/" EnigmaSimulation.sol > EnigmaSimulation.tmp && mv EnigmaSimulation.tmp EnigmaSimulation.sol 19 | sed -e "s/WorkersImpl\./WorkersImplSimulation./g" EnigmaSimulation.sol > EnigmaSimulation.tmp && mv EnigmaSimulation.tmp EnigmaSimulation.sol 20 | 21 | # Check if the existing EnigmaSimulation.sol matches the replacement version 22 | if ! diff EnigmaSimulation.sol $CONTRACTSDIR/EnigmaSimulation.sol > /dev/null 2>&1; then 23 | if [ $FIX = 1 ]; then 24 | mv EnigmaSimulation.sol $CONTRACTSDIR/EnigmaSimulation.sol 25 | else 26 | echo "Error: Enigma.sol and EnigmaSimulation.sol differ more than they should."; 27 | echo "Run this script with --fix to fix the differences automatically." 28 | rm -f EnigmaSimulation.sol 29 | popd > /dev/null 2>&1 30 | exit 1; 31 | fi 32 | else 33 | rm -f EnigmaSimulation.sol 34 | fi 35 | 36 | # Comment out a block to support Simulation Mode in WorkersImpl.sol 37 | sed -e '/require(verifyReportImpl/,/require(signerQuote/ s_^_//_' $IMPLDIR/WorkersImpl.sol > WorkersImplSimulation.sol 38 | sed -e "s/library WorkersImpl /library WorkersImplSimulation /" WorkersImplSimulation.sol > WorkersImplSimulation.tmp && mv WorkersImplSimulation.tmp WorkersImplSimulation.sol 39 | 40 | # Check if the existing WorkersImpl-Simulation matches the above substitution 41 | if ! diff WorkersImplSimulation.sol $IMPLDIR/WorkersImplSimulation.sol > /dev/null 2>&1; then 42 | if [ $FIX = 1 ]; then 43 | mv WorkersImplSimulation.sol $IMPLDIR/WorkersImplSimulation.sol 44 | else 45 | echo "Error: WorkersImpl.sol and WorkersImplSimulation.sol differ more than they should."; 46 | echo "Run this script with --fix to fix the differences automatically." 47 | rm -f WorkersImplSimulation.sol 48 | popd > /dev/null 2>&1 49 | exit 1; 50 | fi 51 | else 52 | rm -f WorkersImplSimulation.sol 53 | fi 54 | 55 | # Replace what needs to be replaced in TaskImpl.sol to support Simulation 56 | sed -e "s#import { WorkersImpl } from \"./WorkersImpl.sol\";#import { WorkersImplSimulation } from \"./WorkersImplSimulation.sol\";#" $IMPLDIR/TaskImpl.sol > TaskImplSimulation.sol 57 | sed -e "s/WorkersImpl\./WorkersImplSimulation./g" TaskImplSimulation.sol > TaskImplSimulation.tmp && mv TaskImplSimulation.tmp TaskImplSimulation.sol 58 | sed -e "s/library TaskImpl /library TaskImplSimulation /" TaskImplSimulation.sol > TaskImplSimulation.tmp && mv TaskImplSimulation.tmp TaskImplSimulation.sol 59 | 60 | # Check if the existing TaskImplSimulation.sol matches the replacement version 61 | if ! diff TaskImplSimulation.sol $IMPLDIR/TaskImplSimulation.sol > /dev/null 2>&1; then 62 | if [ $FIX = 1 ]; then 63 | mv TaskImplSimulation.sol $IMPLDIR/TaskImplSimulation.sol 64 | else 65 | echo "Error: TaskImpl.sol and TaskImplSimulation.sol differ more than they should."; 66 | echo "Run this script with --fix to fix the differences automatically." 67 | rm -f TaskImplSimulation.sol 68 | popd > /dev/null 2>&1 69 | exit 1; 70 | fi 71 | else 72 | rm -f TaskImplSimulation.sol 73 | fi 74 | 75 | # Replace what needs to be replaced in PrincipalImpl.sol to support Simulation 76 | sed -e "s#import { WorkersImpl } from \"./WorkersImpl.sol\";#import { WorkersImplSimulation } from \"./WorkersImplSimulation.sol\";#" $IMPLDIR/PrincipalImpl.sol > PrincipalImplSimulation.sol 77 | sed -e "s/WorkersImpl\./WorkersImplSimulation./g" PrincipalImplSimulation.sol > PrincipalImplSimulation.tmp && mv PrincipalImplSimulation.tmp PrincipalImplSimulation.sol 78 | sed -e "s/library PrincipalImpl /library PrincipalImplSimulation /" PrincipalImplSimulation.sol > PrincipalImplSimulation.tmp && mv PrincipalImplSimulation.tmp PrincipalImplSimulation.sol 79 | 80 | # Check if the existing PrincipalImplSimulation.sol matches the replacement version 81 | if ! diff PrincipalImplSimulation.sol $IMPLDIR/PrincipalImplSimulation.sol > /dev/null 2>&1; then 82 | if [ $FIX = 1 ]; then 83 | mv PrincipalImplSimulation.sol $IMPLDIR/PrincipalImplSimulation.sol 84 | else 85 | echo "Error: PrincipalImpl.sol and PrincipalImplSimulation.sol differ more than they should."; 86 | echo "Run this script with --fix to fix the differences automatically." 87 | rm -f PrincipalImplSimulation.sol 88 | popd > /dev/null 2>&1 89 | exit 1; 90 | fi 91 | else 92 | rm -f PrincipalImplSimulation.sol 93 | fi 94 | 95 | # return to the folder where this script was called from 96 | popd > /dev/null 2>&1 -------------------------------------------------------------------------------- /scripts/copy-contracts-to-enigma-core.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | CORE_PATH=./../../enigma-core-internal 3 | echo -e "Copying built contracts to enigma-core in local path: $CORE_PATH...\n" 4 | cp -v ./../build/contracts/Enigma.json $CORE_PATH/enigma-principal/app/tests/principal_node/contracts/ 5 | cp -v ./../build/contracts/EnigmaToken.json $CORE_PATH/enigma-principal/app/tests/principal_node/contracts/ 6 | echo "Contracts copied successfully" 7 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | git clone https://github.com/enigmampc/discovery-docker-network.git 3 | cd discovery-docker-network/enigma-contract 4 | 5 | if [[ ${TRAVIS_BRANCH} == "master" ]]; then 6 | TAG=latest 7 | else 8 | # ${TRAVIS_BRANCH} == "develop" 9 | TAG=develop 10 | fi 11 | 12 | docker build --build-arg GIT_BRANCH_CONTRACT=$TRAVIS_BRANCH -t enigmampc/enigma_contract:${TAG} --no-cache . 13 | echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin 14 | 15 | docker push enigmampc/enigma_contract:${TAG} 16 | -------------------------------------------------------------------------------- /simulate-coin-mixer.sh: -------------------------------------------------------------------------------- 1 | node ./integration/coin-mixer.js --with-register 2 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | require ('@babel/register') ({ 2 | ignore: [ /node_modules\/(?!openzeppelin-solidity\/test\/helpers)/ ] 3 | }); 4 | require ("core-js/stable"); 5 | require ("regenerator-runtime/runtime"); 6 | 7 | // See 8 | // to customize your Truffle configuration! 9 | module.exports = { 10 | networks: { 11 | develop: { 12 | host: 'localhost', 13 | port: 9545, 14 | network_id: '4447' // Match ganache network id 15 | }, 16 | // This network section is needed for travis-ci, do not remove 17 | ganache: { 18 | host: "127.0.0.1", 19 | port: 8545, 20 | network_id: "2" 21 | }, 22 | // This network section is needed for travis-ci, do not remove 23 | ganache_remote: { 24 | host: "localhost", 25 | port: 30000, 26 | network_id: "3" 27 | } 28 | }, 29 | solc: { 30 | // Turns on the Solidity optimizer. For development the optimizer's 31 | // quite helpful, just remember to be careful, and potentially turn it 32 | // off, for live deployment and/or audit time. For more information, 33 | // see the Truffle 4.0.0 release notes. 34 | // 35 | // https://github.com/trufflesuite/truffle/releases/tag/v4.0.0 36 | optimizer: { 37 | enabled: true, 38 | runs: 200 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /utils/generate-principal-msg-hash.js: -------------------------------------------------------------------------------- 1 | module.exports = function(callback) { 2 | (async () => { 3 | const epoch = { 4 | blockNumber: '10240', 5 | workers: [ 6 | '0x627306090abab3a6e1400e9345bc60c78a8bef57', 7 | '0xf17f52151ebef6c7334fad080c5704d77216b732', 8 | '0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef', 9 | '0x821aea9a577a9b44299b9c15c88cf3087f3b5544', 10 | '0x0d1d4e623d10f9fba5db95830f7d3839406c6af2', 11 | '0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e', 12 | '0x2191ef87e392377ec08e7c08eb105ef5448eced5'], 13 | stakes: ['90000000000', '10000000000', '1000000000', '2000000000', '10000000000', '20000000000', '4000000000'], 14 | nonce: '0', 15 | seed: '50988235200444173608949792536820041636604916839545064578578833583764434511969', 16 | }; 17 | const msg = web3.eth.abi.encodeParameters( 18 | ['uint256', 'uint256', 'address[]', 'uint256[]'], 19 | [epoch.seed, epoch.nonce, epoch.workers, epoch.stakes], 20 | ); 21 | const hash = web3.utils.keccak256(msg); 22 | console.log('The message hash:', hash); 23 | const fromEnclave = 'a7ea85fbd69ef19b047e117761265d5ea3802482d947db60772c15d2ca502c45'; 24 | console.log('The message hash from the enclave', fromEnclave); 25 | callback(); 26 | })(); 27 | }; 28 | -------------------------------------------------------------------------------- /utils/get-active-workers.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | module.exports = function(callback) { 3 | (async () => { 4 | const jsonFile = 'build/contracts/IEnigma.json'; 5 | const parsed = JSON.parse(fs.readFileSync(jsonFile)); 6 | const abi = parsed.abi; 7 | const address = '0xe547Baa852602c90e641d0e9d6B0d279AFC09f92'; 8 | let Enigma = new web3.eth.Contract(abi, address); 9 | const blockNumber = await web3.eth.getBlockNumber(); 10 | console.log('The current block number:', blockNumber); 11 | const accounts = await web3.eth.getAccounts(); 12 | const result = await Enigma.methods.getActiveWorkers(blockNumber).call(); 13 | console.log('The active workers:', result[0], result[1]); 14 | callback(); 15 | })(); 16 | }; 17 | -------------------------------------------------------------------------------- /utils/parse-enigma-abi.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | module.exports = function(callback) { 3 | (async () => { 4 | const jsonFile = 'build/contracts/Enigma.json'; 5 | const parsed = JSON.parse(fs.readFileSync(jsonFile)); 6 | const abi = parsed.abi; 7 | const address = '0x729f735f69B679475edf684C14435e59D23a98e8'; 8 | let Enigma = new web3.eth.Contract(abi, address); 9 | console.log('Got contract object from abi:', Enigma); 10 | callback(); 11 | })(); 12 | }; 13 | -------------------------------------------------------------------------------- /utils/print-receipt.js: -------------------------------------------------------------------------------- 1 | module.exports = function(callback) { 2 | const RECEIPT_HASH = '0x33c3c14e3cd8764911d243e67c229adf7279b3e920a3dbb317ff989946ad47bb'; 3 | const replacer = (name, val) => { 4 | if (web3.utils.isBN(val) || typeof val === 'number' || typeof val === 'boolean') { 5 | return web3.utils.toHex(val); 6 | } else if (val === 0 || val === '0') { 7 | return '0x0'; 8 | } else if (val === null || val === undefined) { 9 | if (name === 'contractAddress') { 10 | // TODO: why empty in Truffle 11 | return web3.utils.toChecksumAddress('0xc1912fee45d61c87cc5ea59dae31190fffff2323'); 12 | } else { 13 | return '0x'; 14 | } 15 | } else { 16 | return val; // return as is 17 | } 18 | }; 19 | 20 | (async () => { 21 | const genesisBlock = await web3.eth.getBlock(0); 22 | console.log('Genesis block hash:', genesisBlock.hash); 23 | const receipt = await web3.eth.getTransactionReceipt(RECEIPT_HASH); 24 | const receiptJson = JSON.stringify(receipt, replacer); 25 | console.log('RECEIPT:', receiptJson); 26 | const blockHash = receipt.blockHash; 27 | const block = await web3.eth.getBlock(blockHash); 28 | const blockJson = JSON.stringify(block, replacer); 29 | console.log('BLOCK:', blockJson); 30 | callback(); 31 | })(); 32 | }; 33 | -------------------------------------------------------------------------------- /utils/register-compare-reports.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const RLP = require('rlp'); 3 | const ADDRS = [ 4 | '0x4800e3f00f9cdbc4420ce4b299855c39455a7bab', 5 | '0x26b97a149ab68740034334375c67afcf125f0caf', 6 | ]; 7 | const REPORTS = [ 8 | '{"id":"27594931944982484559535512292851436992","timestamp":"2019-02-12T18:50:27.368748","isvEnclaveQuoteStatus":"GROUP_OUT_OF_DATE","platformInfoBlob":"1502006504000700000505020401010000000000000000000008000009000000020000000000000AC7E077731D2090E685064D91CD6C1AABDDA629B6BF478D27950D59FCC7E33271333A92D56098E0489FE4339B664ADE4888AA1695B389EC64AFFA2B1D6C1DBECBDD","isvEnclaveQuoteBody":"AgAAAMcKAAAHAAYAAAAAABYB+Vw5ueowf+qruQGtw+6yMPMBSlbDeUQ8w7OHUCgqAgX/BP//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAAAHAAAAAAAAADlca6XQetVGTms5okoNNINkpvtRB41+GLAF+5XJv27MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACD1xnnferKFHD2uvYqTXdDA8iZ22kCD5xw7h38CMfOngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABIAOPwD5zbxEIM5LKZhVw5RVp7qwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}', 9 | '{"id":"138716609621435238003295069316188068770","timestamp":"2019-02-28T21:36:27.356202","isvEnclaveQuoteStatus":"GROUP_OUT_OF_DATE","platformInfoBlob":"1502006504000600000808020401010000000000000000000008000009000000020000000000000AF2A67C01C84D950552687431E3B5F8981D35BD03BFD53D209BCCC1AC5DB9CBE3FEE948C17EC5272A51DC2B2577D25EDD42492877B6AB10F6797463830B65F82917","isvEnclaveQuoteBody":"AgAAAPIKAAAHAAYAAAAAABYB+Vw5ueowf+qruQGtw+4CDn4FRGnk8Z47utdnpaUHCAgCBAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAAAHAAAAAAAAAJL3Z9GBNRUxSNr4s8/vkY9xmejvm2U1D/wewXlk4woNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACD1xnnferKFHD2uvYqTXdDA8iZ22kCD5xw7h38CMfOngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAweDI2Yjk3YTE0OWFiNjg3NDAwMzQzMzQzNzVjNjdhZmNmMTI1ZjBjYWYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}', 10 | ]; 11 | const SIGNS = [ 12 | '57ebd93c7b0c665ad98551a594ad3d7e3593f9ada7ca7ae4625328be23b615dc57a317a14ba4a79426466b2435fc92a1830ceff9828d535642e9e66c3aeba6537e9d5e25495bf290c487de720691f66de643c3497645c27ad278f68e05799d18050bb03e0c280ddc0c29a581fe088f1403c08932b316b77226c8661c17b334f3e68386dd680485a14806e3bf2a6e46ec0be9c9a6eedc4b6f68f3f3f509dc995333a791e875691f1a4e7345ecb8683994ae56ae242f59414dd5f428e738d6c200358f4be556653d3facdf35d1e681a26755889ba42cc1fba0cb17f00879403c5d5f6a42bf08904e4f0e637cad0a20eebb74ce5630c991ab19e1a1fafb116a79e9', 13 | '3c1d6e98082882a2409bea1881e8f4831a7fc6b876e4066f811ad2b438102eb5c12f7c7ac40795675a1c4b73685dc41d1b427016b98cd90333e0f0e830315cfe6a8e5cc8be20fbbe532511da02c1655222345ef5339dcaca4c1e801211764fd6a312555cc63d21b5c6d78615706dafd7aa5606895396d0e6ac6d6ec4b96be1ef3c6c2385381e23d9c5eb4fcc49b1afcb9c2e4638a49251fe7c22f575efad5a300ec91e35d4afaa91c723df3bffc1746e7d93217a9b075199dd7e9b3735af730f2bce1eec39d718e5c86f4a06aefb9936ca5ffb8d30f9484972738f036b05a8bdd15ba03775c9668f1bcfe474f8e05845ea440a6baee1b79b0f4d435b36570fce', 14 | ]; 15 | module.exports = function(callback) { 16 | (async () => { 17 | const jsonInterface = 'build/contracts/IEnigma.json'; 18 | const jsonContract = 'build/contracts/Enigma.json'; 19 | const abi = JSON.parse(fs.readFileSync(jsonInterface)).abi; 20 | const address = JSON.parse(fs.readFileSync(jsonContract)).networks['4447'].address; 21 | let Enigma = new web3.eth.Contract(abi, address); 22 | const blockNumber = await web3.eth.getBlockNumber(); 23 | console.log('The current block number:', blockNumber); 24 | const accounts = await web3.eth.getAccounts(); 25 | for (let [index, signer] of ADDRS.entries()) { 26 | console.log('Registering report for signer', signer, REPORTS[index]); 27 | // const report = '0x' + RLP.encode(REPORTS[index]).toString('hex'); 28 | const report = '0x' + Array.from(REPORTS[index]).map((c) => c.charCodeAt(0).toString(16)).join(''); 29 | const sig = '0x' + SIGNS[index]; 30 | try { 31 | const receipt = await Enigma.methods.register(signer, report, sig).send({ 32 | gas: 4712388, 33 | gasPrice: 100000000000, 34 | from: accounts[index], 35 | }); 36 | console.log('The receipt for worker', signer, receipt); 37 | } catch (e) { 38 | console.log('Unable to register', e); 39 | } 40 | } 41 | callback(); 42 | })(); 43 | }; 44 | --------------------------------------------------------------------------------