├── .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 | [](https://travis-ci.org/enigmampc/enigma-contract) | [](https://codecov.io/gh/enigmampc/enigma-contract) |
6 | | Develop | [](https://travis-ci.org/enigmampc/enigma-contract) | [](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 |
--------------------------------------------------------------------------------