├── .drone.yml
├── .eslintrc.json
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ └── test.yml
├── .gitignore
├── .nvmrc
├── .prettierrc.json
├── .travis.yml
├── Dockerfile
├── LICENSE
├── README.md
├── configs
├── debug.json
└── template1.js
├── docs
├── ARCHITECTURE.md
├── DiscoveryBoot.png
├── FindProvidersAction.png
├── IPC_MESSAGES.md
├── IdentifySyncDiagram.png
├── MainController.jpg
├── NodeControllerDiagrams.jpg
├── ON_BOARDING.md
├── PersistentDiscovery.png
├── SyncHighLevel.png
├── TASKS_LIFE_CYCLE_DOCS.md
├── TrySyncReceiveOneContract.png
├── discovery_sequence
├── jsonrpc.png
├── overview1.jpg
├── overview2.jpg
├── overview3.jpg
├── start_flow.jpg
├── states_sync_sequence
└── streams_diagram_sync.png
├── package-lock.json
├── package.json
├── scripts
├── deploy.sh
└── test_tree_validation.js
├── src
├── cli
│ ├── Parsers.js
│ └── cli_app.js
├── client_api
│ ├── JsonRpcServer.js
│ └── README.md
├── common
│ ├── CIDUtil.js
│ ├── DbUtils.js
│ ├── EncoderUtil.js
│ ├── EngCID.js
│ ├── StoppableTask.js
│ ├── constants.js
│ ├── cryptography.js
│ ├── errors.js
│ ├── logger.js
│ └── utils.js
├── core
│ ├── CoreRuntime.js
│ ├── actions
│ │ ├── DbRead
│ │ │ └── GetDbAction.js
│ │ ├── DbWrite
│ │ │ └── UpdateDbAction.js
│ │ ├── PreParseAction.js
│ │ ├── SendToCoreAction.js
│ │ └── deprecated
│ │ │ ├── GetAllAddrsAction.js
│ │ │ ├── GetContractCodeAction.js
│ │ │ ├── GetDeltasAction.js
│ │ │ └── NewTaskEncryptionKeyAction.js
│ ├── core_messages_scheme.json
│ ├── core_server_mock
│ │ ├── core_server.js
│ │ ├── data
│ │ │ └── provider_db.js
│ │ └── dataGenerator.js
│ └── ipc.js
├── db
│ ├── DbKey.js
│ └── LevelDbApi.js
├── ethereum
│ ├── EnigmaContractAPIBuilder.js
│ ├── EnigmaContractReaderAPI.js
│ ├── EnigmaContractWriterAPI.js
│ ├── EthereumAPI.js
│ ├── EthereumServices.js
│ ├── EthereumVerifier.js
│ ├── StateSync.js
│ └── config.json
├── index.js
├── main_controller
│ ├── DummyRuntime.js
│ ├── EnvironmentBuilder.js
│ ├── FacadeController.js
│ ├── MainController.js
│ ├── actions
│ │ ├── DbAction.js
│ │ ├── DummyAction.js
│ │ └── ProxyAction.js
│ ├── channels
│ │ ├── Channel.js
│ │ ├── Communicator.js
│ │ └── Envelop.js
│ └── mock_tests
│ │ └── IdentifyMissingContentTest.js
├── policy
│ ├── p2p_messages
│ │ ├── messages.js
│ │ ├── principal_messages.js
│ │ ├── schemes
│ │ │ ├── SchemeValidator.js
│ │ │ └── state_sync_scheme.json
│ │ └── sync_messages.js
│ └── policy.js
└── worker
│ ├── EnigmaNode.js
│ ├── builder
│ └── WorkerBuilder.js
│ ├── controller
│ ├── NodeController.js
│ └── actions
│ │ ├── GetRegistrationParamsAction.js
│ │ ├── GetStateKeysAction.js
│ │ ├── GetStatusAction.js
│ │ ├── HealthCheckAction.js
│ │ ├── InitWorkerAction.js
│ │ ├── NewTaskEncryptionKeyAction.js
│ │ ├── PubSubUnsubscribeAction.js
│ │ ├── PubsubPublishAction.js
│ │ ├── PubsubSubscribeAction.js
│ │ ├── SubscribeSelfSignKeyTopicPipelineAction.js
│ │ ├── connectivity
│ │ ├── BootstrapDiscoveredAction.js
│ │ ├── GetPeers.js
│ │ └── NewPeerAction.js
│ │ ├── db
│ │ ├── DbRequestAction.js
│ │ ├── read
│ │ │ ├── GetAllAddrsAction.js
│ │ │ ├── GetAllTipsAction.js
│ │ │ ├── GetContractCodeAction.js
│ │ │ ├── GetDeltasAction.js
│ │ │ └── GetTipsAction.js
│ │ └── write
│ │ │ └── UpdateDbAction.js
│ │ ├── ethereum
│ │ ├── CommitReceiptAction.js
│ │ ├── GetWorkerParamsAction.js
│ │ ├── LoginAction.js
│ │ ├── LogoutAction.js
│ │ ├── RegisterAction.js
│ │ └── UnregisterAction.js
│ │ ├── proxy
│ │ ├── GetStatusProxyAction.js
│ │ ├── ProxyDispatcherAction.js
│ │ ├── RouteRpcBlockingAction.js
│ │ └── RouteRpcNonBlockingAction.js
│ │ ├── sync
│ │ ├── AnnounceContentAction.js
│ │ ├── AnnounceLocalStateAction.js
│ │ ├── FindContentProviderAction.js
│ │ ├── GetLocalTipsOfRemote.js
│ │ ├── IdentifyMissingStatesAction.js
│ │ ├── ProvideSyncStateAction.js
│ │ ├── ReceiveAllPipelineAction.js
│ │ └── TryReceiveAllAction.js
│ │ └── tasks
│ │ ├── ExecuteTaskAction.js
│ │ ├── GetResultAction.js
│ │ ├── HandleVerifiedTaskAction.js
│ │ ├── PublishTaskResultAction.js
│ │ ├── StartTaskExecutionAction.js
│ │ ├── VerifyAndStoreResultAction.js
│ │ └── VerifyNewTaskAction.js
│ ├── handlers
│ ├── ManagementServer.js
│ ├── PrincipalNode.js
│ ├── ProtocolHandler.js
│ └── WebServer.js
│ ├── libp2p-bundle.js
│ ├── state_sync
│ ├── provider
│ │ └── Provider.js
│ └── receiver
│ │ ├── FindProviderResult.js
│ │ ├── LocalMissingStatesResult.js
│ │ ├── Receiver.js
│ │ └── StateSyncReqVerifier.js
│ └── tasks
│ ├── ComputeTask.js
│ ├── DeployTask.js
│ ├── OutsideTask.js
│ ├── Result.js
│ ├── Task.js
│ └── TaskManager.js
└── test
├── all_actions_test.js
├── basic_test.js
├── db_cache_test.js
├── ethereum
├── EnigmaContractMock.js
├── EthereumAPIMock.js
├── advanced_eth_test.js
├── basic_eth_test.js
├── eth_verifier_test.js
├── scripts
│ ├── contracts
│ │ ├── Enigma.sol
│ │ ├── EnigmaToken.sol
│ │ ├── ExchangeRate.sol
│ │ ├── Migrations.sol
│ │ ├── impl
│ │ │ ├── EnigmaCommon.sol
│ │ │ ├── EnigmaEvents.sol
│ │ │ ├── EnigmaState.sol
│ │ │ ├── EnigmaStorage.sol
│ │ │ ├── Getters.sol
│ │ │ ├── PrincipalImpl.sol
│ │ │ ├── SecretContractImpl.sol
│ │ │ ├── TaskImpl.sol
│ │ │ ├── UpgradeImpl.sol
│ │ │ └── WorkersImpl.sol
│ │ ├── interfaces
│ │ │ ├── ERC20.sol
│ │ │ ├── IEnigma.sol
│ │ │ └── IExchangeRate.sol
│ │ └── utils
│ │ │ ├── Base64.sol
│ │ │ ├── Bytes.sol
│ │ │ ├── GetCode2.sol
│ │ │ ├── Memory.sol
│ │ │ └── SolRsaVerify.sol
│ ├── env_initializer.js
│ ├── migrations
│ │ ├── 1_initial_migration.js
│ │ └── 2_deploy_contracts.js
│ └── truffle.js
├── test_parameters.json
└── utils.js
├── init_worker_test.js
├── ipc_test.js
├── jsonrpc_advanced_test.js
├── jsonrpc_test.js
├── msg_test.js
├── nodeutils_test.js
├── principal_test.js
├── singleConfig
├── config_1.js
├── config_2_bootstrap.js
├── id-l.json
└── single_config_test.js
├── sync_basic_test.js
├── sync_network_test.js
├── tasks
├── random_compute_tasks.json
├── random_deploy_tasks.json
├── task_flow_test.js
├── task_manager_test.js
├── task_test.js
└── utils.js
├── testUtils
├── id-d.json
├── id-l.json
├── principal_mock.js
├── quickBuilderUtil.js
└── utils.js
├── test_tree.js
├── utils_test.js
├── verifier_test.js
└── webserver_test.js
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["prettier"],
3 | "plugins": ["prettier"],
4 | "rules": {
5 | "prettier/prettier": "error"
6 | },
7 | "env": {
8 | "es6": true
9 | },
10 | "parserOptions": { "ecmaVersion": 2019 }
11 | }
12 |
--------------------------------------------------------------------------------
/.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 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 |
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 |
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 |
25 | - OS: [e.g. iOS]
26 | - Browser [e.g. chrome, safari]
27 | - Version [e.g. 22]
28 |
29 | **Additional context**
30 | Add any other context about the problem here.
31 |
--------------------------------------------------------------------------------
/.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 | **Is your feature request related to a problem? Please describe.**
10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
11 |
12 | **Describe the solution you'd like**
13 | A clear and concise description of what you want to happen.
14 |
15 | **Describe alternatives you've considered**
16 | A clear and concise description of any alternative solutions or features you've considered.
17 |
18 | **Additional context**
19 | Add any other context or screenshots about the feature request here.
20 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Unit Tests
2 |
3 | on: [push]
4 |
5 | jobs:
6 | test:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - uses: actions/checkout@v1
11 | - uses: actions/setup-node@v1.1.0
12 | with:
13 | node-version: 10.15.3
14 | - run: npm install
15 | - run: npm run test-tree
16 | - run: npm test
17 | - run: npm run report-coverage
18 | env:
19 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
20 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | lts/dubnium
2 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | { "printWidth": 120 }
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - "10.16"
5 |
6 | install:
7 | - npm install
8 |
9 | script:
10 | - npm test
11 | - if [ ${TRAVIS_BRANCH} == "develop" ] || [ ${TRAVIS_BRANCH} == "master" ]; then echo $TRAVIS_BRANCH ; npm run test-tree; fi
12 |
13 | after_success:
14 | - npm run report-coverage
15 |
16 | notifications:
17 | email:
18 | on_success: never
19 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:10
2 | MAINTAINER Isan-Rivkin
3 | WORKDIR /usr/src/app
4 | COPY package*.json ./
5 | RUN npm -g config set user root
6 | RUN npm install
7 | COPY . .
8 | EXPOSE 8080
9 | RUN apt-get update
--------------------------------------------------------------------------------
/configs/debug.json:
--------------------------------------------------------------------------------
1 | {
2 | "bootstrapNodes": [],
3 | "port": "0",
4 | "nickname": "peer",
5 | "multiAddrs": ["/ip4/0.0.0.0/tcp/"],
6 | "namespace": "ipfs",
7 | "idPath": null,
8 | "isDiscover": true
9 | }
10 |
--------------------------------------------------------------------------------
/configs/template1.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | logger: {
3 | level: "debug", // log level
4 | cli: true, // output to std
5 | file: false // output to file, if set path then will save to file else none.
6 | },
7 | node: {
8 | network: {
9 | port: "0", // if 0 then chose random port,
10 | multiAddrs: ["/ip4/0.0.0.0/tcp/"],
11 | // TODO:: ignored because of constants/namespace
12 | namespace: "ipfs"
13 | },
14 | idPath: null, // load PeerId, if null-> create one
15 | // TODO:: ignored currently cuz of implementation
16 | id: null, // either idPath or id -> actuall object here are acceptable if both are set, idPath is the default
17 | // TODO:: ignored libp2p-bundle
18 | isDiscover: true, // should do discovery ?
19 | // the inner task manager of the node controller
20 | taskManager: {
21 | dbPath: null // the db path for storage, if null saves in default
22 | },
23 | // epoch related config
24 | // TODO:: ignored because of constants/PRINCIPAL_NODE
25 | principalNode: {
26 | uri: null, //principal node url, default if null
27 | retryOptions: {
28 | retries: 10, // try 1 time and retry 10 times if needed, total = 11
29 | factor: 1.7, // https://www.wolframalpha.com/input/?i=Sum%5B1000*x%5Ek,+%7Bk,+0,+9%7D%5D+%3D+5+*+60+*+1000
30 | minTimeout: 1 * 1000, // the number of milliseconds before starting the first retry
31 | maxTimeout: 2 * 60 * 1000, // the maximum number of milliseconds between two retries
32 | randomize: true
33 | }
34 | }
35 | },
36 | // IPC
37 | core: {
38 | uri: "tcp://127.0.0.1:5552" // ipc uri
39 | },
40 | // JsonRpc config
41 | proxy: {
42 | withProxy: true, // default serve as a proxy node
43 | port: null // integer or null will default in constants
44 | },
45 | // Ethereum related configuration
46 | ethereum: {
47 | //default use ethereum or not
48 | withEthereum: false,
49 | // websocket provider
50 | ethereumWebsocketProvider: "",
51 | // enigma contract address
52 | enigmaContractAddress: ""
53 | },
54 | // TODO:: CURRENTLY IGNORED
55 | "dev:": {
56 | truffleDir: ""
57 | }
58 | };
59 |
--------------------------------------------------------------------------------
/docs/DiscoveryBoot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/DiscoveryBoot.png
--------------------------------------------------------------------------------
/docs/FindProvidersAction.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/FindProvidersAction.png
--------------------------------------------------------------------------------
/docs/IdentifySyncDiagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/IdentifySyncDiagram.png
--------------------------------------------------------------------------------
/docs/MainController.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/MainController.jpg
--------------------------------------------------------------------------------
/docs/NodeControllerDiagrams.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/NodeControllerDiagrams.jpg
--------------------------------------------------------------------------------
/docs/PersistentDiscovery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/PersistentDiscovery.png
--------------------------------------------------------------------------------
/docs/SyncHighLevel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/SyncHighLevel.png
--------------------------------------------------------------------------------
/docs/TASKS_LIFE_CYCLE_DOCS.md:
--------------------------------------------------------------------------------
1 | # Tasks Life Cycle
2 |
3 | There are 2 type of tasks, Deploy Secret Contracts and Compute something with existing Secret Contracts.
4 |
5 | # Task Manager enigma-p2p
6 |
7 | The TaskManager class is responsible for all the things that are related to the business logic of the tasks life cycle.
8 |
9 | # Task ID
10 |
11 | Every task is identified by its unique global id both in the system and in the network.
12 |
13 | # Task Statuses
14 |
15 |
16 | Unverified
17 | 3 things needs to be verified:
18 |
19 | - The worker verifies it is indeed the selected worker
20 | - The worker verifies the payment details
21 | - The worker verifies the InputsHash
22 |
23 | The task will not be even stored on disk (i.e stay in memory) until it is verified.
24 |
25 |
26 |
27 | In-Progress
28 | Once a task is verified it is sent to `enigma-core` for execution and saved on disk for the purpose of persistence and reduced RAM usage.
29 |
30 |
31 | Success
32 | Indicates that the task was finished successfully. Always includes a result attached.
33 |
34 |
35 | Failed
36 | Indicates that the task execution failed. Always includes an error message.
37 |
38 |
39 | Ethereum-Failure
40 | Indicates that the task failed due to a failure in the Ethereum callback.
41 |
42 |
43 | # Task Result Propagation in the network
44 |
45 | All the task results are either `Failed` or `Success`, and the result is published to a topic called `/task_status/0.1`.
46 | This is how the nodes including the **Gateway** node of the user will be informed once the result is ready.
47 |
48 | # Communication with the selected worker.
49 |
50 | Both for requests and status checks the communication is done via the `JsonRpc` component.
51 | The worker can respond to a status check at any time.
52 |
--------------------------------------------------------------------------------
/docs/TrySyncReceiveOneContract.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/TrySyncReceiveOneContract.png
--------------------------------------------------------------------------------
/docs/jsonrpc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/jsonrpc.png
--------------------------------------------------------------------------------
/docs/overview1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/overview1.jpg
--------------------------------------------------------------------------------
/docs/overview2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/overview2.jpg
--------------------------------------------------------------------------------
/docs/overview3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/overview3.jpg
--------------------------------------------------------------------------------
/docs/start_flow.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/start_flow.jpg
--------------------------------------------------------------------------------
/docs/states_sync_sequence:
--------------------------------------------------------------------------------
1 | /** State sync sequence **/
2 |
3 | This part described the messages and their sequece of a node trying to synchronize its state.
4 |
5 |
6 | Assuming this data structure as a consensus mechanism on the Ethereum network
7 |
8 | // Enigma smart contract stores in some way or another:
9 | +--------------------+----------------+-----------+---------+------+
10 | | secret-contracts | deployed code | delta 1 | delta 2 | ... |
11 | | address | + payload hash | hash | hash | ... |
12 | +--------------------+----------------+-----------+---------+------+
13 | | 0x01... | asd.. | h(d1) | h(d2) | ... |
14 | | 0x02... | bk2.. | h(d1) | h(d2) | ... |
15 | | 0x03... | sg3.. | h(d1) | h(d2) | ... |
16 | | 0x04... | 4fh.. | h(d1) | h(d2) | ... |
17 | +--------------------+----------------+-----------+---------+------+
18 |
19 | ### What does it mean for a worker to by synced ###:
20 |
21 | * CURRENT_ONCHAIN_CONTRACTS_NUM : The total number of contracts.
22 | * CURRENT_ONCHAIN_CONCTRACTS_ADDRS : List of all the contract addresses.
23 | * for each contract addr in CURRENT_ONCHAIN_CONCTRACTS_ADDRS:
24 | * CONTRACT_CODE
25 | * CURRENT_ONCHAIN_DELTAS : List of all the deltas hashes in a sequence order (delta 0 hash = initial state hash)
26 |
27 |
28 |
29 | ### The flow of a new node in the network ####:
30 |
31 | 0) Bootstrap
32 | 1) Load local state
33 | 2) Build "Hits Map" from RemoteState(Ethereum) - LocalState
34 | 3) Sync the "Hits Map" - synchronize from other peers // STATE_SYNC_REQ/RES
35 | 4) Announce (IPFS/CID) holdings (for each contract announce CID(address) )
36 |
37 |
38 | ### State sync request - STATE_SYNC_REQ/RES ###
39 |
40 | // get the most recent tip from a peer
41 | // helpful to verify the peer is holding the state-delta that we need.
42 |
43 | GET_TIP_REQ
44 |
45 | {
46 | msgType : 'GET_TIP_REQ'
47 | contractAddress : '0x...' // the contract address we want to query the last delta from
48 | }
49 | GET_TIP_RES
50 |
51 | {
52 | msgType : 'GET_TIP_RES'
53 | contractAddress : '0x...' // the response include the contract address as well for verification
54 | tipIndex : '' // delta number
55 | tipHash : '' // delta hash keccack256
56 | }
57 |
58 | The message exchange process during #3
59 |
60 |
61 |
62 | After finding the peer CID provider of a contract , request :
63 | The providing peer will respond with up to 500 deltas in each range request, each response is a chunk
64 |
65 |
66 |
67 | SYNC_BCODE_REQ
68 |
69 | {
70 | msgType : 'SYNC_BCODE_REQ'
71 | contractAddress : '0x...' the address of the secret-contract
72 | }
73 | SYNC_BCODE_RES
74 | {
75 | msgType : 'SYNC_BCODE_RES'
76 | contractAddress : '0x...' the address of the secret-contract
77 | deployedByteCode : [] // byte array of the deployed byte code (does not include state[0])
78 | }
79 |
80 |
81 | SYNC_STATE_REQ
82 |
83 | {
84 | msgType : 'SYNC_STATE_REQ'
85 | contractAddress : '0x...' the address of the secret-contract,
86 | fromIndex: '', // start index (include)
87 | toIndex : '', // end index (include)
88 | fromHash : '',
89 | toHash : ''
90 | }
91 |
92 | SYNC_STATE_RES
93 |
94 | {
95 | msgType : 'SYNC_STATE_RES'
96 | contractAddress : '0x...' the address of the secret-contract,
97 | states : [{index,hash,data}...] // the actual state deltas
98 | }
99 |
100 |
101 |
102 |
103 | ### Stream Flow ###
104 |
105 | OnBoot:
106 |
107 | 0) Bootstrap
108 | 1) Load current state from local db
109 | 2) get missing states from ethereum
110 | 3) request states from peers using IPFS
111 | 4) announce synched
112 |
113 | On Provide Request - Stream only flow :
114 |
115 | Requester -> LocalDB -> Requester -> repeat ?
116 |
117 | On Sync Request - Stream only flow :
118 |
119 | Missing state -> Provider Peer -> Sliding Window -> Validate Hashes -> repeat ?
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/docs/streams_diagram_sync.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/scrtlabs/enigma-p2p/95529ba265693196d30844696861b71951d78839/docs/streams_diagram_sync.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "enigma-p2p",
3 | "version": "0.2.6",
4 | "description": "Enigma P2P library based on libp2p-js ",
5 | "main": "src/index.js",
6 | "bin": {
7 | "enigma-p2p-test": "./src/cli/cli_app.js"
8 | },
9 | "nyc": {
10 | "temp-dir": "/tmp/enigma-p2p"
11 | },
12 | "scripts": {
13 | "test": "find ./test -name '*_test.js' | npx nyc xargs env mocha --timeout 200000",
14 | "truffle-develop": "cd ./test/ethereum/scripts && truffle develop",
15 | "truffle-migrate-print-contract-address": "cd ./test/ethereum/scripts; truffle compile >/dev/null; truffle migrate --reset 2>/dev/null | grep -A 4 \"Replacing 'Enigma'\" | grep 'contract address' | awk '{print $NF}'",
16 | "kill-truffle": "ps aux | grep truffle | grep -v grep | awk '{print $2}' | xargs kill -9 || true",
17 | "compile-truffle": "cd test/ethereum/scripts && rm -rf build && truffle compile",
18 | "report-coverage": "npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov",
19 | "lint": "eslint src",
20 | "lint:fix": "eslint --fix src",
21 | "start": "node src/cli/cli_app.js",
22 | "test-tree": "node scripts/test_tree_validation.js"
23 | },
24 | "author": "isan rivkin",
25 | "license": "AGPL-3.0-or-later",
26 | "repository": {
27 | "type": "git",
28 | "url": "https://github.com/enigmampc/enigma-p2p.git"
29 | },
30 | "dependencies": {
31 | "@nodeutils/defaults-deep": "^1.1.0",
32 | "async": "^2.6.1",
33 | "commander": "^2.18.0",
34 | "config": "^3.1.0",
35 | "cors": "^2.8.5",
36 | "ethereumjs-abi": "^0.6.7",
37 | "expect": "^24.1.0",
38 | "express": "^4.17.1",
39 | "fs": "0.0.1-security",
40 | "jayson": "^3.0.1",
41 | "jsbi": "^2.0.5",
42 | "jsonschema": "^1.2.4",
43 | "level": "^4.0.0",
44 | "libp2p": "^0.23.0",
45 | "libp2p-bootstrap": "^0.9.3",
46 | "libp2p-kad-dht": "^0.15.4",
47 | "libp2p-mdns": "^0.12.0",
48 | "libp2p-mplex": "^0.8.0",
49 | "libp2p-pnet": "^0.1.0",
50 | "libp2p-secio": "^0.10.0",
51 | "libp2p-spdy": "^0.12.1",
52 | "libp2p-tcp": "^0.12.1",
53 | "libp2p-websocket-star": "^0.10.0",
54 | "libp2p-websockets": "^0.12.0",
55 | "load-json-file": "^5.1.0",
56 | "log": "^1.4.0",
57 | "log4js": "^6.1.0",
58 | "mocha": "^6.1.4",
59 | "msgpack-lite": "^0.1.26",
60 | "openzeppelin-solidity": "2.1",
61 | "package.json": "^2.0.1",
62 | "peer-info": "^0.14.1",
63 | "pick-random": "^2.0.0",
64 | "randomatic": "^3.1.0",
65 | "readline": "^1.3.0",
66 | "retry": "^0.12.0",
67 | "rimraf": "^2.6.2",
68 | "unix-timestamp": "^0.2.0",
69 | "web3": "1.0.0-beta.37",
70 | "web3-utils": "1.0.0-beta.37",
71 | "zeromq": "^5.1.0",
72 | "date-format": "^3.0.0"
73 | },
74 | "devDependencies": {
75 | "axios": "^0.18.1",
76 | "body-parser": "^1.18.3",
77 | "capture-console": "^1.0.1",
78 | "codecov": "^3.1.0",
79 | "connect": "^3.6.6",
80 | "eslint": "^6.7.2",
81 | "eslint-config-prettier": "^6.7.0",
82 | "eslint-plugin-prettier": "^3.1.2",
83 | "prettier": "^1.19.1",
84 | "tempdir": "^2.0.0",
85 | "truffle": "^5.1.1",
86 | "ws": "^7.0.0"
87 | },
88 | "contributors": [
89 | "Isan Rivkin ",
90 | "Lena Kleyner ",
91 | "Elichai Turkel ",
92 | "Avishai Weingarten ",
93 | "Victor Grau Serrat ",
94 | "Aditya Palepu ",
95 | "Assaf Morami "
96 | ]
97 | }
98 |
--------------------------------------------------------------------------------
/scripts/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | git clone https://github.com/enigmampc/discovery-docker-network.git
3 | cd discovery-docker-network/enigma-p2p
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_P2P=$TRAVIS_BRANCH -t enigmampc/enigma_p2p:${TAG} --no-cache .
13 | echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
14 | docker push enigmampc/enigma_p2p:${TAG}
15 |
--------------------------------------------------------------------------------
/scripts/test_tree_validation.js:
--------------------------------------------------------------------------------
1 | const tree = require("../test/test_tree").TEST_TREE;
2 | let topLevelKeys = Object.keys(tree);
3 | let shouldPanic = false;
4 | topLevelKeys.forEach(tk => {
5 | if (tree[tk].all === false) {
6 | console.log(`[ERROR] test_tree param ${tk} not true`);
7 | shouldPanic = true;
8 | }
9 | let localKeys = Object.keys(tk);
10 | localKeys.forEach(lk => {
11 | if (tree[tk]["#" + lk] === false) {
12 | console.log(`[ERROR] test_tree param ${tk}.#${lk} not true`);
13 | shouldPanic = true;
14 | }
15 | });
16 | });
17 |
18 | if (shouldPanic) {
19 | process.exit(1);
20 | }
21 |
--------------------------------------------------------------------------------
/src/cli/Parsers.js:
--------------------------------------------------------------------------------
1 | module.exports.list = function(val, params) {
2 | const parseVal = val.split(",");
3 | parseVal.forEach(ma => {
4 | let toReplace = "";
5 | let val = "";
6 | if (ma === "B1") {
7 | val = "B1";
8 | toReplace = params.B1Addr;
9 | }
10 | if (ma === "B2") {
11 | val = "B2";
12 | toReplace = params.B2Addr;
13 | }
14 |
15 | const idx = parseVal.indexOf(val);
16 | parseVal[idx] = toReplace;
17 | });
18 | params.configObject.bootstrapNodes = parseVal;
19 | params.changedKeys.push("bootstrapNodes");
20 | return parseVal;
21 | };
22 |
23 | module.exports.nickname = function(val, params) {
24 | const parsedVal = val.toString();
25 | params.configObject.nickname = parsedVal;
26 | params.changedKeys.push("nickname");
27 | return parsedVal;
28 | };
29 |
30 | module.exports.port = function(val, params) {
31 | let parseVal = val.toString();
32 | if (parseVal === "B1") {
33 | parseVal = params.B1Port;
34 | }
35 | if (parseVal === "B2") {
36 | parseVal = params.B2Port;
37 | }
38 | params.configObject.port = parseVal;
39 | params.changedKeys.push("port");
40 | return parseVal;
41 | };
42 |
43 | module.exports.idPath = function(val, params) {
44 | let parsedVal = val.toString();
45 | if (parsedVal === "B1") {
46 | parsedVal = params.B1Path;
47 | }
48 | if (parsedVal === "B2") {
49 | parsedVal = params.B2Path;
50 | }
51 |
52 | params.configObject.idPath = parsedVal;
53 | params.changedKeys.push("idPath");
54 | return parsedVal;
55 | };
56 |
57 | // module.exports.enigmaContractAddress = function(val,params) {
58 | // params.configObject.enigmaContractAddress = val;
59 | // params.changedKeys.push('enigmaContractAddress');
60 | // return val;
61 | // };
62 |
63 | module.exports.opener =
64 | " ______ _ _____ ___ _____ \n" +
65 | " | ____| (_) | __ \\__ \\| __ \\ \n" +
66 | " | |__ _ __ _ __ _ _ __ ___ __ _ | |__) | ) | |__) |\n" +
67 | " | __| | '_ \\| |/ _` | '_ ` _ \\ / _` | | ___/ / /| ___/ \n" +
68 | " | |____| | | | | (_| | | | | | | (_| | | | / /_| | \n" +
69 | " |______|_| |_|_|\\__, |_| |_| |_|\\__,_| |_| |____|_| \n" +
70 | " __/ | \n" +
71 | " |___/ ";
72 |
--------------------------------------------------------------------------------
/src/common/CIDUtil.js:
--------------------------------------------------------------------------------
1 | const CID = require("cids");
2 | const multihash = require("multihashes");
3 | const Web3 = require("web3");
4 |
5 | class CIDUtil {
6 | /**
7 | * The hashing function that is used currently is hashKeccack256 but there is not reason it cannot change.
8 | * @param {Array} delta
9 | * @return {string} hash
10 | * */
11 | static hashByteArray(delta) {
12 | return CIDUtil.hashKeccack256(delta);
13 | }
14 | static hashKeccack256(value) {
15 | return new Web3().utils.sha3(value);
16 | }
17 |
18 | /** cast Ethereum keccack256 function into a CID
19 | * @param {String} ethHash, with 0x len 66, 64 without 0x, both inputs are fine
20 | * @return {CID} cid representing the input.
21 | * */
22 | static createCID(ethHash) {
23 | try {
24 | const h = CIDUtil.parseHashStr(ethHash);
25 | const buffHash = Buffer.from(h, "hex");
26 | const mh = multihash.encode(buffHash, "keccak-256");
27 | return new CID(1, "eth-block", mh, "base58btc");
28 | } catch (err) {
29 | // console.log('[-] err creating cid {%s}', err);
30 | return null;
31 | }
32 | }
33 |
34 | static createCIDFromB58(b58CID) {
35 | try {
36 | return new CID(b58CID);
37 | } catch (err) {
38 | return null;
39 | }
40 | }
41 |
42 | /** remove 0x from the hash if existing
43 | * @param {String} h, keccack256 hash
44 | * @return {String} hash without 0x or the same
45 | * */
46 | static parseHashStr(h) {
47 | let final = null;
48 | if (h.length == 64) {
49 | final = h;
50 | } else if (h.length == 66) {
51 | final = h.substring(2, h.length);
52 | }
53 | return final;
54 | }
55 |
56 | static getKeccak256FromCID(cid) {
57 | try {
58 | return multihash.toHexString(cid.multihash);
59 | } catch (err) {
60 | return null;
61 | }
62 | }
63 |
64 | static isValidCID(cid) {
65 | return CID.isCID(cid);
66 | }
67 | }
68 |
69 | module.exports = CIDUtil;
70 |
--------------------------------------------------------------------------------
/src/common/DbUtils.js:
--------------------------------------------------------------------------------
1 | const Web3 = require("web3");
2 |
3 | class DbUtils {
4 | static toHexString(byteArray) {
5 | return Array.from(byteArray, function(byte) {
6 | return ("0" + (byte & 0xff).toString(16)).slice(-2);
7 | }).join("");
8 | }
9 |
10 | static hexToBytes(hex) {
11 | if (hex.slice(0, 2) === "0x") {
12 | hex = hex.slice(2, hex.length);
13 | }
14 | const b = Buffer.from(hex, "hex");
15 | return [...b];
16 | }
17 |
18 | static intTo4BytesArr(num) {
19 | if (num > 4294967295) {
20 | throw new Error("integer overflow");
21 | }
22 | const arr = new Uint8Array([
23 | (num & 0xff000000) >> 24,
24 | (num & 0x00ff0000) >> 16,
25 | (num & 0x0000ff00) >> 8,
26 | num & 0x000000ff
27 | ]);
28 | return Array.from(arr);
29 | }
30 |
31 | static bytesArrToInt(bytesArr) {
32 | const buf = Buffer.from(bytesArr);
33 | return buf.readUInt32BE(0);
34 | }
35 |
36 | static deltaKeyBytesToTuple(byteKey) {
37 | let addr = byteKey.slice(0, byteKey.length - 4);
38 | addr = DbUtils.toHexString(addr);
39 | let index = byteKey.slice(byteKey.length - 4, byteKey.length);
40 | index = DbUtils.bytesArrToInt(index);
41 | return { address: addr, index: index };
42 | }
43 | static toBytesKey(contractByteAddr, index) {
44 | const res = [];
45 | contractByteAddr.forEach(c => {
46 | res.push(c);
47 | });
48 | if (index >= 0) {
49 | const indexBytes = DbUtils.intTo4BytesArr(index);
50 | indexBytes.forEach(c => {
51 | res.push(c);
52 | });
53 | }
54 | return res;
55 | }
56 | static isValidEthereumAddress(address) {
57 | let web3 = new Web3();
58 | return web3.utils.isAddress(address);
59 | }
60 | }
61 |
62 | module.exports = DbUtils;
63 |
--------------------------------------------------------------------------------
/src/common/EncoderUtil.js:
--------------------------------------------------------------------------------
1 | const msgpack = require("msgpack-lite");
2 |
3 | class EncoderUtil {
4 | static encode(rawObject) {
5 | try {
6 | return msgpack.encode(rawObject);
7 | } catch (e) {
8 | return null;
9 | }
10 | }
11 | static encodeToNetwork(rawObject) {
12 | const encodedBuffer = EncoderUtil.encode(rawObject);
13 | if (encodedBuffer) {
14 | const encodedByteArray = [...encodedBuffer];
15 | return encodedByteArray;
16 | }
17 | return null;
18 | }
19 | static decode(encodedBuffer) {
20 | try {
21 | return msgpack.decode(encodedBuffer);
22 | } catch (e) {
23 | return null;
24 | }
25 | }
26 | static decodeFromNetwork(encodedBytes) {
27 | const encodedBuffer = Buffer.from(encodedBytes);
28 | const decoded = EncoderUtil.decode(encodedBuffer);
29 | return decoded;
30 | }
31 | static hexToAscii(hex) {
32 | if (!(typeof hex === "number" || typeof hex == "string")) {
33 | return "";
34 | }
35 | hex = hex.toString().replace(/\s+/gi, "");
36 | const stack = [];
37 | for (let n = 0; n < hex.length; n += 2) {
38 | const code = parseInt(hex.substr(n, 2), 16);
39 | if (!isNaN(code) && code !== 0) {
40 | stack.push(String.fromCharCode(code));
41 | }
42 | }
43 | return stack.join("");
44 | }
45 | }
46 |
47 | module.exports = EncoderUtil;
48 |
49 | /** * mini tests */
50 | // // take input from Core (encoded) and compare the output
51 | //
52 | // let fromCore = [146, 129, 164, 110, 97, 109, 101, 166, 65, 110, 100, 114, 101,
53 | // 119, 129, 164, 110, 97, 109, 101, 165, 77, 97, 120, 105, 109];
54 | //
55 | // let j = EncoderUtil.decodeFromNetwork(fromCore);
56 | //
57 | // console.log(j);
58 | // // take output obj from network and decode compare with core decoded
59 | //
60 | // let toCore = [{"name":"Andrew"},{"name":"Maxim"}];
61 | //
62 | // let encoded= EncoderUtil.encodeToNetwork(toCore);
63 | //
64 | // console.log(encoded);
65 |
--------------------------------------------------------------------------------
/src/common/EngCID.js:
--------------------------------------------------------------------------------
1 | const CIDUtil = require("./CIDUtil");
2 | const EncoderUtil = require("./EncoderUtil");
3 |
4 | /**
5 | * Abstraction - wrapper to libp2p-cid
6 | * */
7 | class EngCID {
8 | constructor(encoder = EncoderUtil) {
9 | this._encoder = encoder;
10 | this._cid = null;
11 | this._address = null;
12 | }
13 | static createFromByteArray(bytes) {
14 | const h = CIDUtil.hashByteArray(bytes);
15 | return this.createFromKeccack256(h);
16 | }
17 | static createFromSCAddress(scAddr) {
18 | const cid = CIDUtil.createCID(scAddr);
19 | if (cid) {
20 | const engCid = new EngCID();
21 | engCid._setCID(cid);
22 | engCid._setScAddress(scAddr);
23 | return engCid;
24 | }
25 | return null;
26 | }
27 | static createFromKeccack256(keccack256Hash) {
28 | const cid = CIDUtil.createCID(keccack256Hash);
29 | if (cid) {
30 | const engCid = new EngCID();
31 | engCid._setCID(cid);
32 | return engCid;
33 | }
34 | return null;
35 | }
36 | static createFromNetwork(encodedB58byteArray) {
37 | const b58 = EncoderUtil.decodeFromNetwork(encodedB58byteArray);
38 | const cid = CIDUtil.createCIDFromB58(b58);
39 | if (cid) {
40 | const engCID = new EngCID();
41 | engCID._setCID(cid);
42 | return engCID;
43 | }
44 | return null;
45 | }
46 |
47 | getCID() {
48 | return this._cid;
49 | }
50 |
51 | /** get the keccack256 hash of a CID
52 | * @param {Boolean} with0x , if true then add 0x to the result
53 | * @return {String} h, a keccak hash representation
54 | * */
55 | getKeccack256(with0x = false) {
56 | const h = CIDUtil.getKeccak256FromCID(this._cid);
57 | if (with0x) {
58 | return "0x" + h;
59 | }
60 | return h;
61 | }
62 |
63 | toBuffer() {
64 | return this._cid.buffer;
65 | }
66 |
67 | toB58String() {
68 | return this._cid.toBaseEncodedString();
69 | }
70 |
71 | /** Compare if this and other are equal
72 | * @param {CID} cid - other cid to test
73 | * @return {Boolean} true - this.cid == cid , false otherwise*/
74 | equalCID(cid) {
75 | return this._cid.equals(cid);
76 | }
77 |
78 | equalKeccack256(keccackHash) {
79 | const cid = CIDUtil.createCID(keccackHash);
80 | if (cid) {
81 | return this.equalCID(cid);
82 | }
83 | return false;
84 | }
85 |
86 | equalEngCID(engCID) {
87 | if (engCID.constructor.name === "EngCID") {
88 | return this.equalCID(engCID.getCID());
89 | }
90 | return false;
91 | }
92 |
93 | /** Encode the CID into a network stream.
94 | * Steps:
95 | * 1) b58Str = this.cid
96 | * 2) e = encode(b58Str), encode with encoder util, currently msgpack
97 | * 3) b = toBytes(e)
98 | * 4) return b
99 | * @return {Array}
100 | * */
101 | encodeToNetwork() {
102 | return this._encoder.encodeToNetwork(this.toB58String());
103 | }
104 |
105 | _setCID(cid) {
106 | this._cid = cid;
107 | }
108 | _setScAddress(scAddr) {
109 | this._address = scAddr;
110 | }
111 | getScAddress() {
112 | return this._address;
113 | }
114 | }
115 |
116 | module.exports = EngCID;
117 |
118 | // /** examples */
119 | //
120 | // let eth = '0xe8a5770e2c3fa1406d8554a6539335f5d4b82ed50f442a6834149d9122e7f8af';
121 | // let eng = EngCID.createFromKeccack256(eth);
122 | //
123 | // let eth2 = 'e8a5770e2c3fa1406d8554a6539335f5d4b82ed50f442a6834149d9122e7f8af';
124 | // let eng2 = EngCID.createFromKeccack256(eth2);
125 | // let otherCid = new CID(eng2.toB58String());
126 | // console.log("generated " + eng2.equalCID(otherCid));
127 | // console.log(eng.toB58String());
128 | // console.log(eng.toBuffer());
129 | // console.log(eng.getKeccack256());
130 | //
131 | // console.log(eng.equalCID(eng2.getCID()));
132 | // console.log(eng.equalKeccack256(eth2));
133 | // console.log(eng.equalEngCID(eng2));
134 | // //network encoding this
135 | // let fromNetwork = eng.encodeToNetwork();
136 | // let newCID = EngCID.createFromNetwork(fromNetwork);
137 | // console.log(eng.equalEngCID(newCID));
138 |
--------------------------------------------------------------------------------
/src/common/StoppableTask.js:
--------------------------------------------------------------------------------
1 | class StoppableTask {
2 | constructor(options, task, onFinish) {
3 | this._timeout = null;
4 | this._maxRetry = null;
5 | this._taskInput = null;
6 | this._delay = 0;
7 |
8 | this._onFinish = onFinish;
9 |
10 | if (options.timeout) {
11 | this._timeout = options.timeout;
12 | }
13 | if (options.maxRetry) {
14 | this._maxRetry = options.maxRetry;
15 | }
16 | if (options.taskInput) {
17 | this._taskInput = options.taskInput;
18 | }
19 |
20 | if (options.delay) {
21 | this._delay = options.delay;
22 | }
23 |
24 | this._tryCount = -1;
25 | this._stop = false;
26 | this._task = task;
27 | this._timerId = null;
28 | }
29 |
30 | start() {
31 | if (this._timeout) {
32 | this._timerId = setTimeout(() => {
33 | this._stop = true;
34 | }, this._timeout);
35 | }
36 |
37 | if (this._tryCount > -1) {
38 | this._tryCount = 0;
39 | }
40 |
41 | this._execute();
42 | }
43 | _execute() {
44 | setTimeout(() => {
45 | if (this._taskInput) {
46 | this._task(this._taskInput, this);
47 | } else {
48 | this._task(this);
49 | }
50 | }, this._delay);
51 | }
52 | done(status, result) {
53 | if (status.success) {
54 | this._finish(status, result);
55 | } else {
56 | if (this._shouldStop()) {
57 | this._finish(status, result);
58 | } else {
59 | this._tryCount += 1;
60 | this._execute();
61 | }
62 | }
63 | }
64 | _finish(status, result) {
65 | clearTimeout(this._timerId);
66 | this._onFinish(status, result);
67 | }
68 |
69 | _shouldStop() {
70 | let shouldStop = false;
71 |
72 | if (this._maxRetry != null) {
73 | if (this._tryCount >= this._maxRetry) {
74 | shouldStop = true;
75 | }
76 | }
77 |
78 | return this._stop || shouldStop;
79 | }
80 | }
81 |
82 | module.exports = StoppableTask;
83 |
84 | // let job = (params, stopper)=>{
85 | // console.log("i run " + params.val);
86 | // stopper.done({"success" : false} , 42);
87 | // };
88 | //
89 | // let onFinish = (status, result)=>{
90 | // if(status.success){
91 | // console.log("yay success " + result);
92 | // }else{
93 | // console.log("failed!");
94 | // }
95 | // };
96 | //
97 | // let task = new StoppableTask({
98 | // "maxRetry" : 2,
99 | // "timeout" : 2000,
100 | // "taskInput" : {"val" : 11},
101 | // "delay" : 500,
102 | // },job,onFinish);
103 | //
104 | // task.start();
105 |
--------------------------------------------------------------------------------
/src/common/cryptography.js:
--------------------------------------------------------------------------------
1 | const web3Utils = require("web3-utils");
2 | const errors = require("./errors");
3 | const JSBI = require("jsbi");
4 | const utils = require("../common/utils");
5 |
6 | /**
7 | * hash parameters in order
8 | * @param {Array} value of byte arrrays
9 | * @param {boolean} with0x optional defaults to true
10 | * @return {string} hash
11 | * */
12 | module.exports.hash = (value, with0x = true) => {
13 | let h = _keccack256Hash(value);
14 | if (!with0x && h.length > 2 && h.slice(0, 2) === "0x") {
15 | h = h.substr(2);
16 | }
17 | return h;
18 | };
19 |
20 | /**
21 | * Hash parameters in order, mimicking the way solidity is doing that
22 | * The function receives any number of parameters
23 | * @return {string} hash
24 | * */
25 | module.exports.soliditySha3 = function() {
26 | return web3Utils.soliditySha3.apply(null, arguments);
27 | };
28 |
29 | /**
30 | * Convert any given value to JSBI instance for handling big numbers
31 | * @param {String/Number/HEX} value to convert to BigNumber
32 | * @return {JSBI} converted value
33 | * */
34 | module.exports.toBN = value => {
35 | return JSBI.BigInt(value);
36 | };
37 |
38 | /**
39 | * Generate a hash of all inputs
40 | * The Enigma contract uses the same logic to generate a matching taskId
41 | *
42 | * @param {array} inputsArray
43 | * @return {string} hash of inputs
44 | */
45 | module.exports.hashArray = inputsArray => {
46 | let hexStr = "";
47 | for (let e of inputsArray) {
48 | e = utils.remove0x(e);
49 | // since the inputs are in hex string, they are twice as long as their bytes
50 | hexStr +=
51 | JSBI.BigInt(e.length / 2)
52 | .toString(16)
53 | .padStart(16, "0") + e;
54 | }
55 | return web3Utils.soliditySha3({ t: "bytes", v: hexStr });
56 | };
57 |
58 | /**
59 | * internal
60 | * */
61 | const _keccack256Hash = value => {
62 | return web3Utils.keccak256(Buffer.from(value, "hex"));
63 | };
64 |
--------------------------------------------------------------------------------
/src/common/logger.js:
--------------------------------------------------------------------------------
1 | const log4js = require("log4js");
2 | const constants = require("./constants");
3 | const LOG_CONFIG = constants.LOG_CONFIG;
4 | const format = require("date-format");
5 |
6 | class Logger {
7 | constructor(options = {}) {
8 | const logName = options.hasOwnProperty("name") ? options.name : "Logger";
9 | const logLevel = options.hasOwnProperty("level") ? options.level : LOG_CONFIG.level;
10 |
11 | log4js.configure({
12 | appenders: {
13 | file: {
14 | type: "file",
15 | filename: LOG_CONFIG.file,
16 | maxLogSize: 10 * 1024 * 1024, // = 10Mb
17 | backups: 5, // keep five backup files
18 | compress: true, // compress the backups
19 | encoding: "utf-8",
20 | mode: 0o0640,
21 | flags: "w+"
22 | },
23 | out: {
24 | type: "stdout",
25 | layout: {
26 | type: "pattern",
27 | pattern: "%x{getTime}Z %[%p%] [P2P-%c] - %m",
28 | tokens: {
29 | getTime: function(logEvent) {
30 | return format.asString("yyyy-MM-ddThh:mm:ss", new Date(new Date().toUTCString().slice(0, -4)));
31 | }
32 | }
33 | }
34 | },
35 | err: {
36 | type: "stderr",
37 | layout: {
38 | type: "pattern",
39 | pattern: "%x{getTime}Z %[%p%] [P2P-%c] - %m",
40 | tokens: {
41 | getTime: function(logEvent) {
42 | return format.asString("yyyy-MM-ddThh:mm:ss", new Date(new Date().toUTCString().slice(0, -4)));
43 | }
44 | }
45 | }
46 | },
47 | cli: {
48 | type: "stdout",
49 | layout: {
50 | type: "pattern",
51 | pattern: "%x{getTime}Z [CLI] %m",
52 | tokens: {
53 | getTime: function(logEvent) {
54 | return format.asString("yyyy-MM-ddThh:mm:ss", new Date(new Date().toUTCString().slice(0, -4)));
55 | }
56 | }
57 | }
58 | }
59 | },
60 | categories: {
61 | [logName]: { appenders: ["file", "out"], level: logLevel, enableCallStack: true },
62 | cli: { appenders: ["cli"], level: "info" },
63 | default: { appenders: ["err"], level: "info" }
64 | }
65 | });
66 | this.logger = log4js.getLogger(logName);
67 | }
68 | debug(content) {
69 | this.logger.debug(content);
70 | }
71 | info(content) {
72 | this.logger.info(content);
73 | }
74 | error(content) {
75 | this.logger.error(content);
76 | }
77 | warning(content) {
78 | this.logger.warn(content);
79 | }
80 | fatal(content) {
81 | this.logger.fatal(content);
82 | }
83 | trace(content) {
84 | this.logger.trace(content);
85 | }
86 | }
87 |
88 | module.exports = Logger;
89 |
--------------------------------------------------------------------------------
/src/core/actions/DbRead/GetDbAction.js:
--------------------------------------------------------------------------------
1 | const Envelop = require("../../../main_controller/channels/Envelop");
2 | const nodeUtils = require("../../../common/utils");
3 | const Msg = require("../../../common/constants").CORE_REQUESTS;
4 |
5 | class GetDbAction {
6 | constructor(coreRuntime) {
7 | this._coreRuntime = coreRuntime;
8 | }
9 |
10 | execute(envelop) {
11 | const request = {
12 | id: envelop.content().id,
13 | type: envelop.content().type,
14 | input: envelop.content().input
15 | };
16 | this._coreRuntime.execCmd(Msg.CORE_DB_ACTION, {
17 | envelop: envelop,
18 | sendMsg: request
19 | });
20 | // let client = this._coreRuntime.getIpcClient();
21 | // client.sendJsonAndReceive(,(responseMsg)=>{
22 | // const resEnv = new Envelop(envelop.id(),responseMsg, envelop.type());
23 | // this._coreRuntime.getCommunicator()
24 | // .send(resEnv);
25 | // });
26 | }
27 | }
28 | module.exports = GetDbAction;
29 |
--------------------------------------------------------------------------------
/src/core/actions/DbWrite/UpdateDbAction.js:
--------------------------------------------------------------------------------
1 | const Envelop = require("../../../main_controller/channels/Envelop");
2 | const constants = require("../../../common/constants");
3 | const nodeUtils = require("../../../common/utils");
4 |
5 | class UpdateDbAction {
6 | constructor(coreRuntime) {
7 | this._coreRuntime = coreRuntime;
8 | }
9 | static _buildRequest(msgObj) {
10 | let request = {
11 | id: nodeUtils.randId(),
12 | type: null
13 | };
14 | // from topic published - already parsed
15 | if (msgObj.type && typeof msgObj.type !== "function") {
16 | return msgObj;
17 | }
18 | // from sync process
19 | if (msgObj.type() === constants.P2P_MESSAGES.SYNC_STATE_RES) {
20 | request.type = constants.CORE_REQUESTS.UpdateDeltas;
21 | request.deltas = msgObj.deltas();
22 | } else if (msgObj.type() === constants.P2P_MESSAGES.SYNC_BCODE_RES) {
23 | request.type = constants.CORE_REQUESTS.UpdateNewContract;
24 | request.address = msgObj.address();
25 | request.bytecode = msgObj.bytecode();
26 | }
27 | if (request.type) return request;
28 | return null;
29 | }
30 | execute(envelop) {
31 | /***/
32 | let request = UpdateDbAction._buildRequest(envelop.content().input);
33 | this._coreRuntime.execCmd(constants.CORE_REQUESTS.CORE_DB_ACTION, {
34 | envelop: envelop,
35 | sendMsg: request
36 | });
37 | /***/
38 | }
39 | }
40 | module.exports = UpdateDbAction;
41 |
--------------------------------------------------------------------------------
/src/core/actions/PreParseAction.js:
--------------------------------------------------------------------------------
1 | const Envelop = require("../../main_controller/channels/Envelop");
2 | const nodeUtils = require("../../common/utils");
3 | const Msg = require("../../common/constants").CORE_REQUESTS;
4 |
5 | class PreParseAction {
6 | constructor(coreRuntime) {
7 | this._coreRuntime = coreRuntime;
8 | }
9 | execute(envelop) {
10 | let request = envelop.content();
11 | this._coreRuntime.execCmd(Msg.CORE_DB_ACTION, {
12 | envelop: envelop,
13 | sendMsg: request
14 | });
15 | }
16 | }
17 | module.exports = PreParseAction;
18 |
--------------------------------------------------------------------------------
/src/core/actions/SendToCoreAction.js:
--------------------------------------------------------------------------------
1 | const Envelop = require("../../main_controller/channels/Envelop");
2 |
3 | class SendToCoreAction {
4 | constructor(coreRuntime) {
5 | this._coreRuntime = coreRuntime;
6 | }
7 | execute(params) {
8 | const sendMsg = params.sendMsg;
9 | const envelop = params.envelop;
10 | const client = this._coreRuntime.getIpcClient();
11 | if (!sendMsg.id) {
12 | sendMsg.id = envelop.id();
13 | }
14 | client
15 | .sendJsonAndReceive(sendMsg, (err, responseMsg) => {
16 | if (err) {
17 | console.error(`[Error] Failed in Send JSON And Receive: ${err}`);
18 | responseMsg = { error: err };
19 | }
20 | const resEnv = new Envelop(envelop.id(), responseMsg, envelop.type());
21 | this._coreRuntime.getCommunicator().send(resEnv);
22 | })
23 | .catch(console.error);
24 | }
25 | }
26 | module.exports = SendToCoreAction;
27 |
--------------------------------------------------------------------------------
/src/core/actions/deprecated/GetAllAddrsAction.js:
--------------------------------------------------------------------------------
1 | const Envelop = require("../../../main_controller/channels/Envelop");
2 | const nodeUtils = require("../../../common/utils");
3 | const Msg = require("../../../common/constants").CORE_REQUESTS;
4 |
5 | class GetAllAddrsAction {
6 | constructor(coreRuntime) {
7 | this._coreRuntime = coreRuntime;
8 | }
9 | execute(envelop) {
10 | /***/
11 | let request = {
12 | id: nodeUtils.randId(),
13 | type: Msg.GetAllAddrs
14 | };
15 | this._coreRuntime.execCmd(Msg.CORE_DB_ACTION, {
16 | envelop: envelop,
17 | sendMsg: request
18 | });
19 | /***/
20 | }
21 | }
22 | module.exports = GetAllAddrsAction;
23 |
--------------------------------------------------------------------------------
/src/core/actions/deprecated/GetContractCodeAction.js:
--------------------------------------------------------------------------------
1 | const Envelop = require("../../../main_controller/channels/Envelop");
2 | const nodeUtils = require("../../../common/utils");
3 | const Msg = require("../../../common/constants").CORE_REQUESTS;
4 |
5 | class GetContractCodeAction {
6 | constructor(coreRuntime) {
7 | this._coreRuntime = coreRuntime;
8 | }
9 | execute(envelop) {
10 | /***/
11 | let request = {
12 | id: nodeUtils.randId(),
13 | type: Msg.GetContract,
14 | input: envelop.content().input
15 | };
16 | this._coreRuntime.execCmd(Msg.CORE_DB_ACTION, {
17 | envelop: envelop,
18 | sendMsg: request
19 | });
20 | /***/
21 | }
22 | }
23 | module.exports = GetContractCodeAction;
24 |
--------------------------------------------------------------------------------
/src/core/actions/deprecated/GetDeltasAction.js:
--------------------------------------------------------------------------------
1 | const Envelop = require("../../../main_controller/channels/Envelop");
2 | const nodeUtils = require("../../../common/utils");
3 | const Msg = require("../../../common/constants").CORE_REQUESTS;
4 |
5 | class GetDeltasAction {
6 | constructor(coreRuntime) {
7 | this._coreRuntime = coreRuntime;
8 | }
9 | execute(envelop) {
10 | /***/
11 | let request = {
12 | id: nodeUtils.randId(),
13 | type: Msg.GetDeltas,
14 | input: envelop.content().input
15 | };
16 | this._coreRuntime.execCmd(Msg.CORE_DB_ACTION, {
17 | envelop: envelop,
18 | sendMsg: request
19 | });
20 | /***/
21 | }
22 | }
23 | module.exports = GetDeltasAction;
24 |
--------------------------------------------------------------------------------
/src/core/actions/deprecated/NewTaskEncryptionKeyAction.js:
--------------------------------------------------------------------------------
1 | const Envelop = require("../../../main_controller/channels/Envelop");
2 | const nodeUtils = require("../../../common/utils");
3 | const Msg = require("../../../common/constants").CORE_REQUESTS;
4 |
5 | class NewTaskEncryptionKeyAction {
6 | constructor(coreRuntime) {
7 | this._coreRuntime = coreRuntime;
8 | }
9 | execute(envelop) {
10 | let request = envelop.content();
11 | this._coreRuntime.execCmd(Msg.CORE_DB_ACTION, {
12 | envelop: envelop,
13 | sendMsg: request
14 | });
15 | }
16 | }
17 | module.exports = NewTaskEncryptionKeyAction;
18 |
--------------------------------------------------------------------------------
/src/core/core_server_mock/dataGenerator.js:
--------------------------------------------------------------------------------
1 | // DB = {
2 | // 'address' : {
3 | // bytecode : [0,0,0,0,0,...]
4 | // delta : [{
5 | // index : 11,
6 | // data : [243,56,66758,657876]
7 | // }]
8 | // }
9 | // }
10 |
11 | const DbUtil = require("../../common/DbUtils");
12 | const ADDR_SIZE = 32;
13 | const BCODE_SIZE = 1500;
14 | const DELTA_SIZE = 450;
15 |
16 | const fs = require("fs");
17 |
18 | module.exports.appendToFile = (path, file) => {
19 | return new Promise((res, rej) => {
20 | _appendToFile(path, file, err => {
21 | if (err) {
22 | rej(err);
23 | } else {
24 | res();
25 | }
26 | });
27 | });
28 | };
29 | function _appendToFile(path, file, callback) {
30 | fs.appendFile(path, file, function(err) {
31 | callback(err);
32 | });
33 | }
34 | function getRandomInt(max) {
35 | return Math.floor(Math.random() * Math.floor(max));
36 | }
37 | function generateHexAddress() {
38 | let byteAddr = [];
39 | for (let i = 0; i < ADDR_SIZE; ++i) {
40 | byteAddr.push(getRandomInt(255));
41 | }
42 | return DbUtil.toHexString(byteAddr);
43 | }
44 | function generateByteCode() {
45 | let byteCode = [];
46 | for (let i = 0; i < BCODE_SIZE; ++i) {
47 | byteCode.push(getRandomInt(255));
48 | }
49 | return byteCode;
50 | }
51 | function generateDelta() {
52 | let byteDelta = [];
53 | for (let i = 0; i < DELTA_SIZE; ++i) {
54 | byteDelta.push(getRandomInt(255));
55 | }
56 | return byteDelta;
57 | }
58 | // generate a database
59 | function generateData(contractsNum, deltasNum) {
60 | let db = {};
61 | for (let i = 0; i < contractsNum; ++i) {
62 | let contract = {};
63 | contract.address = generateHexAddress();
64 | contract.bytecode = generateByteCode();
65 | contract.deltas = [];
66 | for (let j = 0; j < deltasNum; ++j) {
67 | let delta = {
68 | index: j,
69 | data: generateDelta()
70 | };
71 | contract.deltas.push(delta);
72 | }
73 | db[contract.address] = contract;
74 | }
75 | return db;
76 | }
77 | // generate partial database from a given database
78 | function generatePartialData(db, contractsNum, deltasNum) {
79 | let newDb = {};
80 | let addresses = Object.keys(db);
81 | for (let i = 0; i < contractsNum; i++) {
82 | let contract = db[addresses[i]];
83 | let newDeltas = [];
84 | for (let j = 0; j < Math.min(deltasNum, contract.deltas.length); ++j) {
85 | newDeltas.push(contract.deltas[j]);
86 | }
87 | newDb[contract.address] = contract;
88 | newDb[contract.address].deltas = newDeltas;
89 | }
90 | return newDb;
91 | }
92 |
93 | /** how to generate data && save to file */
94 | // let db = generateData(3, 3);
95 | //let file = 'module.exports.DB_PROVIDER=' + JSON.stringify(db);
96 | // const fs = require('fs');
97 | //
98 | // fs.writeFile('./here.js', file, function(err) {
99 | // if (err) {
100 | // return console.log(err);
101 | // }
102 | // console.log('The file was saved!');
103 | // });
104 | /** how to load the db*/
105 | // let db2 = require('./here');
106 | // console.log(db2.DB_PROVIDER);
107 |
108 | /** how to generate a partial db from a given db */
109 | // let db = generateData(3,3);
110 | // let newDb = generatePartialData(db,2,1);
111 |
--------------------------------------------------------------------------------
/src/db/DbKey.js:
--------------------------------------------------------------------------------
1 | const DbUtils = require("../common/DbUtils");
2 |
3 | class DbKey {
4 | constructor(byteKey, hexAddr, idx) {
5 | this._byteKey = byteKey;
6 | this._hexAddr = hexAddr;
7 | this._idx = idx;
8 | this._isContract = true;
9 | if (idx) {
10 | this._isContract = false;
11 | }
12 | if (this._hexAddr && this._hexAddr.slice(0, 2) === "0x") {
13 | this._hexAddr = this._hexAddr.slice(2);
14 | }
15 | }
16 | /** key builder
17 | * create a key pointing to bytecode
18 | * represented by addr only
19 | * @param {String} addr, secret-contract address
20 | * @return {DbKey} dbKey
21 | */
22 | static fromContractAddr(addr) {
23 | const byteAddr = DbUtils.hexToBytes(addr);
24 | return new DbKey(byteAddr, addr);
25 | }
26 | /** key builder
27 | * create a key pointing to bytecode
28 | * represented by addr only
29 | * @param {Array} byteAddr, secret contract address
30 | * @return {DbKey} dbKey
31 | */
32 | static fromContractBytes(byteAddr) {
33 | const addr = DbUtils.toHexString(byteAddr);
34 | return new DbKey(byteAddr, addr);
35 | }
36 | /** key builder
37 | * @param {String} addr, secret-contract address
38 | * @param {Integer} idx , state delta id
39 | * @return {DbKey} dbKey
40 | */
41 | static fromDeltaTouple(addr, idx) {
42 | const byteAddr = DbUtils.hexToBytes(addr);
43 | const byteKey = DbUtils.toBytesKey(byteAddr, idx);
44 | return new DbKey(byteKey, addr, idx);
45 | }
46 | /** key builder
47 | * @param {Array} byteKey
48 | * @return {DbKey}
49 | */
50 | static fromDeltaBytes(byteKey) {
51 | const tuple = DbUtils.deltaKeyBytesToTuple(byteKey);
52 | return new DbKey(byteKey, tuple.address, tuple.index);
53 | }
54 | isContract() {
55 | return this._isContract;
56 | }
57 | isDelta() {
58 | return !this.isContract();
59 | }
60 | getIndex() {
61 | return this._idx;
62 | }
63 | getAddress() {
64 | return this._hexAddr;
65 | }
66 | getBytesKey() {
67 | return this._byteKey;
68 | }
69 | equals(otherDbKey) {
70 | if (this.isContract() && otherDbKey.isContract()) {
71 | const equal = this.getAddress() === otherDbKey.getAddress();
72 | return equal;
73 | } else if (this.isDelta() && otherDbKey.isDelta()) {
74 | const equal = this.getAddress() === otherDbKey.getAddress();
75 | return equal && this.getIndex() === otherDbKey.getIndex();
76 | } else {
77 | return false;
78 | }
79 | }
80 | }
81 |
82 | module.exports = DbKey;
83 |
--------------------------------------------------------------------------------
/src/ethereum/EthereumAPI.js:
--------------------------------------------------------------------------------
1 | const EthereumServices = require("./EthereumServices");
2 | const EthereumVerifier = require("./EthereumVerifier");
3 | const EnigmaContractAPIBuilder = require("./EnigmaContractAPIBuilder");
4 | const utils = require("../common/utils");
5 |
6 | class EthereumAPI {
7 | constructor(logger) {
8 | this._logger = logger;
9 | this._environment = null;
10 | this._url = null;
11 | this._enigmaContractAddress = null;
12 | this._api = null;
13 | this._verifier = null;
14 | this._services = null;
15 | }
16 |
17 | /**
18 | * check the connectivity to the Ethereum node
19 | * @param {JSON} config
20 | * {ethereumAddress - wallet address,
21 | * enigmaContractAddress - the contract address
22 | * ethereumUrlProvider - the network url
23 | * }
24 | * */
25 | async init(config) {
26 | let builder = new EnigmaContractAPIBuilder(this._logger);
27 | let res = await builder.setConfigAndBuild(config);
28 |
29 | this._api = res.api;
30 | this._environment = res.environment;
31 | this._url = res.url;
32 | this._enigmaContractAddress = res.enigmaContractAddress;
33 |
34 | this._services = new EthereumServices(this._api);
35 | this._services.initServices(null);
36 |
37 | this._verifier = new EthereumVerifier(this._api, this._services, this._logger);
38 | await this._verifier.init();
39 | }
40 |
41 | async destroy() {
42 | await this._environment.destroy();
43 | }
44 |
45 | /**
46 | * check the connectivity to the Ethereum node
47 | * @return {JSON}
48 | * {isConnected - a flag describing the connectivity state,
49 | * blockNumber - Ethereum block number
50 | * url - the network url
51 | * enigmaContractAddress - the contract address
52 | * }
53 | * */
54 | async healthCheck() {
55 | let connected = null;
56 | let blockNumber = null;
57 |
58 | try {
59 | blockNumber = await utils.getEthereumBlockNumber(this._api.w3());
60 | connected = true;
61 | } catch (e) {
62 | this._logger.debug("Error received while trying to read Ethereum block number: " + e);
63 | connected = false;
64 | }
65 |
66 | return {
67 | isConnected: connected,
68 | blockNumber: blockNumber,
69 | url: this._url,
70 | enigmaContractAddress: this._enigmaContractAddress
71 | };
72 | }
73 |
74 | api() {
75 | return this._api;
76 | }
77 |
78 | verifier() {
79 | return this._verifier;
80 | }
81 |
82 | services() {
83 | return this._services;
84 | }
85 | }
86 |
87 | module.exports = EthereumAPI;
88 |
--------------------------------------------------------------------------------
/src/ethereum/EthereumServices.js:
--------------------------------------------------------------------------------
1 | const EventEmitter = require("events");
2 |
3 | const constants = require("../common/constants");
4 |
5 | let servicesMap = {};
6 |
7 | servicesMap[constants.ETHEREUM_EVENTS.NewEpoch] = [constants.RAW_ETHEREUM_EVENTS.WorkersParameterized];
8 | servicesMap[constants.ETHEREUM_EVENTS.TaskCreation] = [constants.RAW_ETHEREUM_EVENTS.TaskRecordCreated];
9 | servicesMap[constants.ETHEREUM_EVENTS.TaskSuccessSubmission] = [constants.RAW_ETHEREUM_EVENTS.ReceiptVerified];
10 | servicesMap[constants.ETHEREUM_EVENTS.TaskFailureSubmission] = [constants.RAW_ETHEREUM_EVENTS.ReceiptFailed];
11 | servicesMap[constants.ETHEREUM_EVENTS.TaskFailureDueToEthereumCB] = [constants.RAW_ETHEREUM_EVENTS.ReceiptFailedETH];
12 | servicesMap[constants.ETHEREUM_EVENTS.TaskCancelled] = [constants.RAW_ETHEREUM_EVENTS.TaskFeeReturned];
13 | servicesMap[constants.ETHEREUM_EVENTS.SecretContractDeployment] = [
14 | constants.RAW_ETHEREUM_EVENTS.SecretContractDeployed
15 | ];
16 |
17 | class EthereumServices extends EventEmitter {
18 | /**
19 | * {EnigmaContractReaderAPI} enigmaContractAPI
20 | *
21 | * */
22 | constructor(enigmaContractAPI) {
23 | super();
24 | this._api = enigmaContractAPI;
25 | this._servicesMap = servicesMap;
26 | }
27 |
28 | /**
29 | * init services
30 | * @param {Array} desiredServices
31 | * */
32 | initServices(desiredServices) {
33 | if (desiredServices !== undefined && desiredServices !== null) {
34 | desiredServices.forEach(service => {
35 | this._initService(service);
36 | });
37 | } else {
38 | Object.keys(this._servicesMap).forEach(service => {
39 | this._initService(service);
40 | });
41 | }
42 | }
43 |
44 | _initService(serviceName) {
45 | this._servicesMap[serviceName].forEach(eventName => {
46 | this._api.subscribe(eventName, {}, (err, event) => {
47 | if (err) {
48 | this.emit(serviceName, err);
49 | } else {
50 | event.type = serviceName;
51 | this.emit(serviceName, null, event);
52 | }
53 | });
54 | });
55 | }
56 | }
57 |
58 | module.exports = EthereumServices;
59 |
--------------------------------------------------------------------------------
/src/ethereum/StateSync.js:
--------------------------------------------------------------------------------
1 | const DbUtils = require("../common/DbUtils");
2 |
3 | /**
4 | * Queries the Enigma contract and returns the comparison between the local tips and the consensus states
5 | * @param {EnigmaContractReaderAPI} api
6 | * @param {Array} localTips [{address,key,delta},...}]
7 | * @return {Promise} returning a JSON: missingList - missing states [{address, deltas : [deltaHash, index]}].
8 | * In case the entire contract is missing, the bytecodeHash is returned as well:
9 | * [{address, bytecodeHash , deltas : [deltaHash, index]}]
10 | * excessList - excessive states [{address, remoteTip, localTip].
11 | * In case the entire contract is excessive, the remoteTip field is set to -1
12 | * */
13 |
14 | async function compareLocalStateToRemote(api, localTips) {
15 | // create a hashmap from the localTips array
16 | return new Promise(async (resolve, reject) => {
17 | const tipsMap = localTips.reduce((obj, item) => {
18 | let address = item.address;
19 | if (typeof address !== "string") {
20 | address = DbUtils.toHexString(address);
21 | }
22 | obj[address] = item.key;
23 | return obj;
24 | }, {});
25 |
26 | let missingList = [];
27 | let excessList = [];
28 |
29 | try {
30 | const remoteSecretContractsAddresses = await api.getAllSecretContractAddresses();
31 | // First go over the remote secret contract tp compare state
32 | for (let secretContractAddress of remoteSecretContractsAddresses) {
33 | const contractData = await api.getContractParams(secretContractAddress);
34 | let missingAddress = false;
35 | let firstMissingIndex;
36 | let missingCodeHash;
37 | let missingDeltas = [];
38 | // get the local tip index, if exists; otherwise 0
39 | if (secretContractAddress in tipsMap) {
40 | firstMissingIndex = tipsMap[secretContractAddress] + 1;
41 | // we delete the secret contract from the tipsHash in order to check if there are excessive contracts locally (in the end of the loop)
42 | delete tipsMap[secretContractAddress];
43 | }
44 | // the address does not exist at the local db, set the firstMissingIndex to 0 and request the codehash
45 | else {
46 | firstMissingIndex = 0;
47 | missingAddress = true;
48 | missingCodeHash = contractData.codeHash;
49 | }
50 | // check if the local state has left over deltas
51 | if (firstMissingIndex > contractData.deltaHashes.length) {
52 | excessList.push({
53 | address: secretContractAddress,
54 | remoteTip: contractData.deltaHashes.length - 1,
55 | localTip: firstMissingIndex - 1
56 | });
57 | }
58 | for (let i = firstMissingIndex; i < contractData.deltaHashes.length; i++) {
59 | missingDeltas.push({
60 | deltaHash: contractData.deltaHashes[i],
61 | index: i
62 | });
63 | }
64 | if (missingDeltas.length) {
65 | if (missingAddress === true) {
66 | missingList.push({
67 | address: secretContractAddress,
68 | deltas: missingDeltas,
69 | bytecodeHash: missingCodeHash
70 | });
71 | } else {
72 | missingList.push({
73 | address: secretContractAddress,
74 | deltas: missingDeltas
75 | });
76 | }
77 | }
78 | }
79 | // Now check that there are no excessive contracts locally
80 | for (let secretContractAddress of Object.keys(tipsMap)) {
81 | excessList.push({ address: secretContractAddress, remoteTip: -1, localTip: tipsMap[secretContractAddress] });
82 | }
83 | } catch (err) {
84 | return reject(err);
85 | }
86 | resolve({ missingList, excessList });
87 | });
88 | }
89 |
90 | module.exports = { compareLocalStateToRemote: compareLocalStateToRemote };
91 |
--------------------------------------------------------------------------------
/src/ethereum/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "default": {
3 | "gas": 3000000
4 | },
5 | "valid": {
6 | "gasMin": 21000,
7 | "gasMax": 8000000,
8 | "gasPriceMin": 3,
9 | "gasPriceMax": 100
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | module.exports.Builder = require("./main_controller/EnvironmentBuilder");
2 | module.exports.cryptography = require("./common/cryptography");
3 | module.exports.Utils = {
4 | nodeUtils: require("./common/utils"),
5 | dbUtils: require("./common/DbUtils")
6 | };
7 |
--------------------------------------------------------------------------------
/src/main_controller/DummyRuntime.js:
--------------------------------------------------------------------------------
1 | const Envelop = require("./channels/Envelop");
2 |
3 | class DummyRuntime {
4 | constructor() {
5 | this._communicator = null;
6 | }
7 | setChannel(communicator) {
8 | this._communicator = communicator;
9 | this._communicator.setOnMessage(envelop => {
10 | console.log("DummyRuntime: got msg : " + JSON.stringify(envelop.content()));
11 | });
12 | }
13 | sendMsg(content) {
14 | const envelop = new Envelop(true, content, "dummy");
15 | console.log("sending id -> " + envelop.id());
16 | this._communicator.sendAndReceive(envelop).then(resEnv => {
17 | console.log("got response id -> " + resEnv.id());
18 | console.log("response content -> " + JSON.stringify(resEnv.content()));
19 | });
20 | }
21 | type() {
22 | return "dummy";
23 | }
24 | }
25 |
26 | module.exports = DummyRuntime;
27 |
--------------------------------------------------------------------------------
/src/main_controller/FacadeController.js:
--------------------------------------------------------------------------------
1 | const MainController = require("./MainController");
2 | const constants = require("../common/constants");
3 | const runtimesTypes = constants.RUNTIME_TYPE;
4 |
5 | /**
6 | * Exposes a concrete API to all the components
7 | * Should be instantiated instead of MainController (general implementation)
8 | * This exposes an API that a CLI can interface with, for example.
9 | * TODO:: implement concrete methods
10 | * TODO:: for now can use getNode(), getIpcClient() etc...
11 | * */
12 | class FacadeController extends MainController {
13 | constructor(runtimes) {
14 | super(runtimes);
15 | this._runtimesMap = {};
16 | try {
17 | runtimes.forEach(rt => {
18 | this._runtimesMap[rt.type()] = rt;
19 | });
20 | } catch (e) {
21 | throw new Error("Runtime does not implement type()");
22 | }
23 | }
24 |
25 | getNode() {
26 | return this._runtimesMap[runtimesTypes.Node];
27 | }
28 |
29 | getIpcClient() {
30 | return this._runtimesMap[runtimesTypes.Core];
31 | }
32 |
33 | getJsonRpcServer() {
34 | return this._runtimesMap[runtimesTypes.JsonRpc];
35 | }
36 |
37 | async shutdownSystem() {
38 | if (this.getJsonRpcServer()) {
39 | this.getJsonRpcServer().close();
40 | }
41 | this.getIpcClient().disconnect();
42 | await this.getNode().stop();
43 | }
44 | }
45 |
46 | module.exports = FacadeController;
47 |
--------------------------------------------------------------------------------
/src/main_controller/actions/DbAction.js:
--------------------------------------------------------------------------------
1 | const constatnts = require("../../common/constants");
2 |
3 | class DbAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 | execute(reqCommunicator, envelop) {
8 | //TODO:: go to db and get all tips
9 | if (envelop.id()) {
10 | // pass to core
11 | //TODO:: rethink this "return" cuz if happens its not normal. comment out and run jsonrpc_test #6
12 | if (!this._controller.getCommunicator(constatnts.RUNTIME_TYPE.Core)) {
13 | return;
14 | }
15 | let dbCommunicator = this._controller.getCommunicator(constatnts.RUNTIME_TYPE.Core).thisCommunicator;
16 | dbCommunicator.sendAndReceive(envelop).then(resEnv => {
17 | reqCommunicator.send(resEnv);
18 | });
19 | }
20 | }
21 | }
22 | module.exports = DbAction;
23 |
--------------------------------------------------------------------------------
/src/main_controller/actions/DummyAction.js:
--------------------------------------------------------------------------------
1 | const Envelop = require("../channels/Envelop");
2 |
3 | class DummyAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 | execute(communicator, envelop) {
8 | if (envelop.id()) {
9 | console.log("Action: got " + envelop.type() + " " + JSON.stringify(envelop.content()));
10 | console.log("Action: sending back envelop");
11 | const type = "dummy";
12 | // if we need another runtime communicator
13 | // let dbCommunicator = this._controller.getCommunicator("db");
14 | // now send messages to db for example
15 | //
16 | const resEnv = new Envelop(envelop.id(), { response: "some response data" }, type);
17 | communicator.send(resEnv);
18 | }
19 | }
20 | }
21 |
22 | module.exports = DummyAction;
23 |
--------------------------------------------------------------------------------
/src/main_controller/actions/ProxyAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../common/constants");
2 |
3 | class ProxyAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 | execute(reqCommunicator, envelop) {
8 | if (envelop.id()) {
9 | this._controller
10 | .getCommunicator(constants.RUNTIME_TYPE.Node)
11 | .thisCommunicator.sendAndReceive(envelop)
12 | .then(resEnv => {
13 | reqCommunicator.send(resEnv);
14 | });
15 | }
16 | }
17 | }
18 | module.exports = ProxyAction;
19 |
--------------------------------------------------------------------------------
/src/main_controller/channels/Channel.js:
--------------------------------------------------------------------------------
1 | const Communicator = require("./Communicator");
2 |
3 | class Channel {
4 | /**
5 | * Creates a bi-directional channel
6 | * @return {Object} {channel1, channel2}
7 | * */
8 | static biDirectChannel() {
9 | const c1 = new Communicator();
10 | const c2 = new Communicator(c1);
11 | c1._setCommunicator(c2);
12 | return { channel1: c1, channel2: c2 };
13 | }
14 | }
15 |
16 | module.exports = Channel;
17 |
--------------------------------------------------------------------------------
/src/main_controller/channels/Communicator.js:
--------------------------------------------------------------------------------
1 | const EventEmitter = require("events").EventEmitter;
2 |
3 | class Communicator extends EventEmitter {
4 | constructor(otherCommunicator) {
5 | super();
6 | this._M = "m";
7 | this._other = otherCommunicator;
8 | }
9 | _setCommunicator(other) {
10 | this._other = other;
11 | }
12 | send(envelop) {
13 | if (envelop.id()) {
14 | this.emit(envelop.id(), envelop);
15 | } else {
16 | this.emit(this._M, envelop);
17 | }
18 | }
19 | sendAndReceive(envelop) {
20 | return new Promise((res, rej) => {
21 | // assumption: the responder will emit id() event
22 | this._other.on(envelop.id(), responseEnvelop => {
23 | res(responseEnvelop);
24 | });
25 | // emit the message
26 | this.emit(this._M, envelop);
27 | });
28 | }
29 | setOnMessage(callback) {
30 | this._other.on(this._M, envelop => {
31 | callback(envelop);
32 | });
33 | }
34 | }
35 |
36 | module.exports = Communicator;
37 | //
38 | // async function test(){
39 | //
40 | // let c1 = new Communicator();
41 | // let c2 = new Communicator(c1);
42 | // c1._setCommunicator(c2);
43 | //
44 | // let e = new Envelop(true,{"req":"123"});
45 | //
46 | // c2.setOnMessage((envelop)=>{
47 | //
48 | // if(envelop.id()){
49 | //
50 | // c2.send(new Envelop(envelop.id(),{"res":"456"}));
51 | // }else{
52 | // console.log("w/e stateless");
53 | // }
54 | //
55 | // });
56 | // let eRes = await c1.sendAndReceive(e);
57 | // console.log("got response => " + JSON.stringify(eRes.content()));
58 | // c1.send(new Envelop(false,{"stateless" : [1,2,3,4]}));
59 | // }
60 | //
61 | // test();
62 |
--------------------------------------------------------------------------------
/src/main_controller/channels/Envelop.js:
--------------------------------------------------------------------------------
1 | const nodeUtils = require("../../common/utils");
2 |
3 | class Envelop {
4 | /** @param {Boolean/string} sequenceOrId
5 | * -- if sequenceOrId is True generate new random id, if sequenceOrId is a string=> it is already id. (hence the name ;-) )
6 | * @param {Object} obj, the data being passed
7 | * @param {string} msgType , used by the MainController to identify which runtime should be called */
8 | constructor(sequenceOrId, obj, msgType) {
9 | this._validEnvelop = true;
10 | //TODO:: this does not actually THROW it just hangs in there without any signal
11 | if (!sequenceOrId || !obj || !msgType) {
12 | console.log("[-] error initializing envelop sequenceOrId,obj,msgType must be specified!");
13 | this._validEnvelop = false;
14 | }
15 | this._msgType = msgType;
16 | this._obj = obj;
17 | this._id = false;
18 | // for response envelop we reuse the id from the original request
19 | if (sequenceOrId && nodeUtils.isString(sequenceOrId)) {
20 | this._id = sequenceOrId;
21 | } else if (sequenceOrId === true) {
22 | // initialize a request with id for response
23 | this._id = nodeUtils.randId();
24 | } else {
25 | console.log(
26 | "[-] error initializing envelop sequenceOrId must be either a string ID or a `true` to generate one randomally!"
27 | );
28 | this._validEnvelop = false;
29 | }
30 | // attach id to msg if missing
31 | if (!("id" in this._obj) && this._id !== false) {
32 | this._obj.id = nodeUtils.randId();
33 | }
34 | }
35 | isValidEnvelop() {
36 | return this._validEnvelop;
37 | }
38 | type() {
39 | return this._msgType;
40 | }
41 | id() {
42 | return this._id;
43 | }
44 | content() {
45 | return this._obj;
46 | }
47 | }
48 |
49 | module.exports = Envelop;
50 |
--------------------------------------------------------------------------------
/src/main_controller/mock_tests/IdentifyMissingContentTest.js:
--------------------------------------------------------------------------------
1 | // const EnvironmentBuilder = require('../EnvironmentBuilder');
2 | // const utils = require('../../common/utils');
3 | // const CoreServer = require('../../core/core_server_mock/core_server');
4 | //
5 | // const peerConfig = {
6 | // 'bootstrapNodes': [],
7 | // 'port': '0',
8 | // 'nickname': 'peer',
9 | // 'idPath': null,
10 | // };
11 | //
12 | // async function test(){
13 | // const uri = 'tcp://127.0.0.1:5555';
14 | // // start the server (core)
15 | // let coreServer = new CoreServer();
16 | // coreServer.runServer(uri);
17 | // await utils.sleep(1500);
18 | // // start the client (enigma-p2p)
19 | // let builder = new EnvironmentBuilder();
20 | // let mainController = await builder
21 | // .setNodeConfig(peerConfig)
22 | // .setIpcConfig({uri : uri})
23 | // .build();
24 | // await utils.sleep(5000);
25 | // let fromCache = false;
26 | // mainController.getNode().identifyMissingStates(fromCache,(missingStates)=>{
27 | // console.log("got the missing states. success");
28 | // console.log(JSON.stringify(missingStates));
29 | // });
30 | // }
31 | // // test();
32 |
--------------------------------------------------------------------------------
/src/policy/p2p_messages/principal_messages.js:
--------------------------------------------------------------------------------
1 | class MsgPrincipal {
2 | constructor(request, sig, addresses, blockNumber) {
3 | this._request = request;
4 | this._sig = sig;
5 | this._blockNumber = blockNumber;
6 | this._addresses = addresses;
7 | Object.freeze(this);
8 | }
9 |
10 | static build(jsonObj) {
11 | if (jsonObj && jsonObj.request && jsonObj.sig) {
12 | const blockNumber = jsonObj.blockNumber ? jsonObj.blockNumber : null;
13 | const addresses = jsonObj.addresses ? jsonObj.addresses : null;
14 | return new MsgPrincipal(jsonObj.request, jsonObj.sig, addresses, blockNumber);
15 | } else {
16 | return null;
17 | }
18 | }
19 |
20 | getRequest() {
21 | return this._request;
22 | }
23 |
24 | getSig() {
25 | return this._sig;
26 | }
27 |
28 | getBlockNumber() {
29 | return this._blockNumber;
30 | }
31 |
32 | getAddresses() {
33 | return this._addresses;
34 | }
35 |
36 | toJson() {
37 | let dict = {
38 | data: this._request,
39 | sig: this._sig
40 | };
41 | if (this._blockNumber) {
42 | dict.block_number = this._blockNumber.toString();
43 | }
44 | if (this._addresses) {
45 | dict.addresses = this._addresses;
46 | }
47 | return dict;
48 | }
49 | }
50 |
51 | module.exports = MsgPrincipal;
52 |
--------------------------------------------------------------------------------
/src/policy/p2p_messages/schemes/state_sync_scheme.json:
--------------------------------------------------------------------------------
1 | {
2 | "SYNC_STATE_REQ": {
3 | "id": "/SYNC_STATE_REQ",
4 | "type": "object",
5 | "properties": {
6 | "msgType": { "type": "string" },
7 | "contractAddress": { "type": "string" },
8 | "fromIndex": { "type": "number" },
9 | "toIndex": { "type": "number" },
10 | "fromHash": { "type": "string" },
11 | "toHash": { "type": "string" }
12 | },
13 | "required": ["msgType", "contractAddress", "fromIndex", "toIndex", "fromHash", "toHash"]
14 | },
15 | "SYNC_STATE_RES": {
16 | "id": "/SYNC_STATE_RES",
17 | "type": "object",
18 | "properties": {
19 | "msgType": { "type": "string" },
20 | "contractAddress": { "type": "string" },
21 | "states": { "type": "list" }
22 | },
23 | "required": ["msgType", "contractAddress", "states"]
24 | },
25 | "SYNC_BCODE_REQ": {
26 | "id": "/SYNC_BCODE_REQ",
27 | "type": "object",
28 | "properties": {
29 | "msgType": { "type": "string" },
30 | "contractAddress": { "type": "string" }
31 | },
32 | "required": ["msgType", "contractAddress"]
33 | },
34 | "SYNC_BCODE_RES": {
35 | "id": "/SYNC_BCODE_RES",
36 | "type": "object",
37 | "properties": {
38 | "msgType": { "type": "string" },
39 | "contractAddress": { "type": "string" },
40 | "deployedByteCode": { "type": "list" }
41 | },
42 | "required": ["msgType", "contractAddress", "deployedByteCode"]
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/policy/policy.js:
--------------------------------------------------------------------------------
1 | /** Policy class that handles messages policy*/
2 | const constants = require("../common/constants");
3 | const PROTOCOLS = constants.PROTOCOLS;
4 | const PUBSUB_TOPICS = constants.PUBSUB_TOPICS;
5 |
6 | class Policy {
7 | constructor() {}
8 | /** is a valid procol name
9 | * @param {String} protocolName,
10 | * @return {Boolean}, is valid protocol
11 | */
12 | isValidProtocol(protocolName) {
13 | for (const key in PROTOCOLS) {
14 | if (PROTOCOLS[key] === protocolName) {
15 | return true;
16 | }
17 | }
18 | return false;
19 | }
20 | /**
21 | * is a valid topic name
22 | * @param {String} topicName
23 | * @return {Boolean} , is valid topic
24 | */
25 | isValidTopic(topicName) {
26 | for (const key in PUBSUB_TOPICS) {
27 | if (PUBSUB_TOPICS[key] === topicName) {
28 | return true;
29 | }
30 | }
31 | return false;
32 | }
33 | /** Validate JSON RPC message type
34 | * @param {Json} msg, some json
35 | * @return {Boolean} isValid
36 | */
37 | validJsonRpc(msg) {
38 | return "jsonrpc" in msg && (("method" in msg && "params") || "result" in msg) && "id" in msg;
39 | }
40 | }
41 |
42 | module.exports = Policy;
43 |
--------------------------------------------------------------------------------
/src/worker/builder/WorkerBuilder.js:
--------------------------------------------------------------------------------
1 | /**
2 | * isDiscover : true/false
3 | * Config:
4 | * bootstrapNodes : [],
5 | * port : 0, otherwise number
6 | * nickname : "nick1" optional,
7 | * multiAddrs : ['/ip4/0.0.0.0/tcp/']
8 | * namespace : 'ipfs',
9 | * idPath : '/path/to/id' or null,
10 | */
11 |
12 | const constants = require("../../common/constants");
13 | const EnigmaNode = require("../EnigmaNode");
14 | const ProtocolHandler = require("../handlers/ProtocolHandler");
15 |
16 | /** WIP - load the node configration
17 | * @param {String} path, path to config or default in /config/debug.json
18 | * @return {Json} configObj
19 | * */
20 | module.exports.loadConfig = function(path) {
21 | return _loadConfig(path);
22 | };
23 | /** WIP - build the Node given a config object
24 | * @param {Json} config
25 | * @param {Logger} logger
26 | * @return {EnigmaNode} engNode
27 | * */
28 | module.exports.build = function(config, logger) {
29 | return _buildNode(config, logger);
30 | };
31 |
32 | function _loadConfig(path) {
33 | let config = null;
34 | if (path) {
35 | config = require(path);
36 | } else {
37 | config = require(constants.configPath);
38 | }
39 | return Object.assign({}, config, {});
40 | }
41 |
42 | function _buildNode(config, logger) {
43 | const options = {};
44 | options.isDiscover = config.isDiscover;
45 | const maAddrs = config.multiAddrs;
46 | options.multiAddrs = [];
47 | options.dnsNodes = config.bootstrapNodes;
48 | options.namespace = config.namespace;
49 | options.port = config.port;
50 | options.nickname = config.nickname;
51 | options.pathPeerId = config.idPath;
52 | // parsed multi-addrs with port
53 | maAddrs.forEach(ma => {
54 | options.multiAddrs.push(ma + options.port);
55 | });
56 |
57 | return new EnigmaNode(options, new ProtocolHandler(logger), logger);
58 | }
59 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/GetRegistrationParamsAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../common/constants");
2 | const Envelop = require("../../../main_controller/channels/Envelop");
3 | class GetRegistrationParamsAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 | execute(params) {
8 | const onResponse = params.onResponse;
9 | const requestEnvelop = new Envelop(
10 | true,
11 | { type: constants.CORE_REQUESTS.GetRegistrationParams },
12 | constants.MAIN_CONTROLLER_NOTIFICATIONS.DbRequest
13 | );
14 |
15 | this._controller
16 | .communicator()
17 | .sendAndReceive(requestEnvelop)
18 | .then(responseEnvelop => {
19 | onResponse(null, responseEnvelop.content());
20 | });
21 | }
22 | }
23 | module.exports = GetRegistrationParamsAction;
24 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/GetStateKeysAction.js:
--------------------------------------------------------------------------------
1 | const MsgPrincipal = require("../../../policy/p2p_messages/principal_messages");
2 | const constants = require("../../../common/constants");
3 |
4 | class GetStateKeysAction {
5 | constructor(controller) {
6 | this._controller = controller;
7 | }
8 |
9 | asyncExecute(params) {
10 | const action = this;
11 | return new Promise((resolve, reject) => {
12 | if (!params) {
13 | params = {};
14 | }
15 | params.onResponse = function(err, data) {
16 | if (err) reject(err);
17 | else resolve(data);
18 | };
19 | action.execute(params);
20 | });
21 | }
22 |
23 | execute(params) {
24 | let onResponse;
25 | if (params && params.onResponse) {
26 | onResponse = params.onResponse;
27 | } else {
28 | onResponse = () => {};
29 | }
30 |
31 | // First, set PTT flag (and validate that no PTT is in progress now)
32 | if (!this._controller.principal().startPTT()) {
33 | const err = "PTT in progress.. aborting GetStateKeysAction";
34 | this._controller.logger().error(err);
35 | return onResponse(err);
36 | }
37 | this._controller.logger().info(`Starting PTT`);
38 | const onPTTRequestResponse = async (err, coreResponse) => {
39 | if (err || coreResponse.type === "Error") {
40 | if (coreResponse && coreResponse.type === "Error") {
41 | err = coreResponse.msg;
42 | }
43 | return this._handleError(
44 | `Failed Core connection: err: ${JSON.stringify(err)}, coreResponse: ${JSON.stringify(coreResponse)}`,
45 | err,
46 | onResponse
47 | );
48 | }
49 |
50 | let principalResponse;
51 | try {
52 | principalResponse = await this._controller
53 | .principal()
54 | .getStateKeys(this._buildRequestMsg(coreResponse, params));
55 | } catch (err) {
56 | // TODO: Errors.
57 | return this._handleError(`Failed Principal node connection: ${err.code} - ${err.message}`, err, onResponse);
58 | }
59 | this._pttResponse({ response: principalResponse.data, sig: principalResponse.sig }, (err, response) => {
60 | if (err || response.type === "Error" || response.result.errors.length > 0) {
61 | if (response && coreResponse.type === "Error") {
62 | err = coreResponse.msg;
63 | } else if (response && response.result && response.result.errors.length > 0) {
64 | err = response.result;
65 | }
66 | return this._handleError(
67 | `Failed Core connection: err: ${JSON.stringify(err)}, coreResponse: ${JSON.stringify(response)}`,
68 | err,
69 | onResponse
70 | );
71 | }
72 | this._controller.principal().onPTTEnd();
73 | return onResponse(null);
74 | });
75 | };
76 |
77 | let dbRequestParams = {
78 | dbQueryType: constants.CORE_REQUESTS.GetPTTRequest,
79 | onResponse: onPTTRequestResponse
80 | };
81 |
82 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.DB_REQUEST, dbRequestParams);
83 | }
84 |
85 | _pttResponse(params, cb) {
86 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.DB_REQUEST, {
87 | dbQueryType: constants.CORE_REQUESTS.PTTResponse,
88 | input: params,
89 | onResponse: cb
90 | });
91 | }
92 |
93 | _buildRequestMsg(coreResponse, params) {
94 | let msg = {
95 | request: coreResponse.result.request,
96 | sig: coreResponse.result.workerSig
97 | };
98 | if (params) {
99 | if (params.addresses) {
100 | msg.addresses = params.addresses;
101 | }
102 | if (params.blockNumber) {
103 | msg.blockNumber = params.blockNumber;
104 | }
105 | }
106 | return MsgPrincipal.build(msg);
107 | }
108 |
109 | _handleError(errMsg, err, onResponse) {
110 | this._controller.logger().error(errMsg);
111 | this._controller.principal().onPTTEnd();
112 | onResponse(err);
113 | }
114 | }
115 |
116 | module.exports = GetStateKeysAction;
117 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/GetStatusAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../common/constants");
2 |
3 | class GetStatusAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 |
8 | /**
9 | * @param {Function} callback (err)=>{}
10 | * */
11 | async execute(params) {
12 | const callback = params.callback;
13 | const C = constants.NODE_NOTIFICATIONS;
14 | let status = null;
15 | let error = null;
16 |
17 | if (this._controller.isWorkerInitInProgress()) {
18 | status = constants.WORKER_STATUS.INITIALIZING;
19 | } else {
20 | try {
21 | const workerParams = await this._controller.asyncExecCmd(C.GET_ETH_WORKER_PARAM);
22 | switch (workerParams.status) {
23 | case constants.ETHEREUM_WORKER_STATUS.UNREGISTERED:
24 | status = constants.WORKER_STATUS.UNREGISTERED;
25 | break;
26 | case constants.ETHEREUM_WORKER_STATUS.LOGGEDIN:
27 | status = constants.WORKER_STATUS.LOGGEDIN;
28 | break;
29 | case constants.ETHEREUM_WORKER_STATUS.LOGGEDOUT:
30 | status = constants.WORKER_STATUS.REGISTERED;
31 | break;
32 | }
33 | } catch (err) {
34 | this._controller.logger().warning("reading worker params from ethereum failed: " + err);
35 | error = err;
36 | }
37 | }
38 | callback(error, status);
39 | }
40 |
41 | asyncExecute(params) {
42 | const action = this;
43 | return new Promise((resolve, reject) => {
44 | params.callback = function(err, res) {
45 | if (err) {
46 | reject(err);
47 | } else {
48 | resolve(res);
49 | }
50 | };
51 | action.execute(params);
52 | });
53 | }
54 | }
55 |
56 | module.exports = GetStatusAction;
57 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/HealthCheckAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../common/constants");
2 |
3 | class HealthCheckAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 |
8 | /**
9 | * @param {Function} callback (err)=>{}
10 | * */
11 | execute(params) {
12 | const callback = params.callback;
13 | const C = constants.NODE_NOTIFICATIONS;
14 |
15 | let healthCheckResult = {
16 | status: false,
17 | core: {
18 | status: false,
19 | registrationParams: {
20 | signKey: null
21 | }
22 | },
23 | ethereum: {
24 | status: false,
25 | uri: null,
26 | contract_addr: null
27 | },
28 | connectivity: {
29 | status: false,
30 | connections: null
31 | }
32 | // TODO: consider adding a periodic, once there
33 | /*state: {
34 | status: false,
35 | missing: null
36 | }*/
37 | };
38 |
39 | this._controller.execCmd(C.REGISTRATION_PARAMS, {
40 | onResponse: async (err, regParams) => {
41 | if (!err) {
42 | // core
43 | healthCheckResult.core.registrationParams.signKey = regParams.result.signingKey;
44 | healthCheckResult.core.status = healthCheckResult.core.registrationParams.signKey != null;
45 |
46 | // ethereum
47 | if (this._controller.hasEthereum()) {
48 | try {
49 | let eth = await this._controller.ethereum().healthCheck();
50 | healthCheckResult.ethereum.uri = eth.url;
51 | healthCheckResult.ethereum.contract_addr = eth.enigmaContractAddress;
52 | healthCheckResult.ethereum.status = eth.isConnected;
53 | } catch (err) {
54 | healthCheckResult.ethereum.status = false;
55 | }
56 | }
57 |
58 | // connectivity
59 | healthCheckResult.connectivity.connections = this._controller.engNode().getConnectedPeers().length;
60 | healthCheckResult.connectivity.status = healthCheckResult.connectivity.connections >= 1;
61 |
62 | healthCheckResult.status =
63 | healthCheckResult.core.status && healthCheckResult.ethereum.status && healthCheckResult.connectivity.status; // && healthCheckResult.state.status;
64 | callback(null, healthCheckResult);
65 | }
66 | }
67 | });
68 | }
69 |
70 | asyncExecute(params) {
71 | const action = this;
72 | return new Promise((resolve, reject) => {
73 | params.callback = function(err, res) {
74 | if (err) {
75 | reject(err);
76 | } else {
77 | resolve(res);
78 | }
79 | };
80 | action.execute(params);
81 | });
82 | }
83 | }
84 |
85 | module.exports = HealthCheckAction;
86 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/NewTaskEncryptionKeyAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../common/constants");
2 | const Envelop = require("../../../main_controller/channels/Envelop");
3 | class NewTaskEncryptionKeyAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 | execute(params) {
8 | const onResponse = params.onResponse;
9 | const requestEnvelop = new Envelop(
10 | params.request.id,
11 | params.request,
12 | constants.MAIN_CONTROLLER_NOTIFICATIONS.DbRequest
13 | );
14 | let err = null;
15 | if (!requestEnvelop.isValidEnvelop()) {
16 | err = "invalid envelop";
17 | }
18 | this._controller
19 | .communicator()
20 | .sendAndReceive(requestEnvelop)
21 | .then(responseEnvelop => {
22 | onResponse(err, responseEnvelop.content());
23 | });
24 | }
25 | }
26 | module.exports = NewTaskEncryptionKeyAction;
27 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/PubSubUnsubscribeAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../common/constants");
2 | const TOPICS = constants.PUBSUB_TOPICS;
3 |
4 | // TODO:: after pr https://github.com/ipfs/interface-js-ipfs-core/pull/437
5 | class PubSubUnsubscribeAction {
6 | constructor(controller) {
7 | this._controller = controller;
8 | }
9 | /** subscribe to to self ethereum signing key topic - useful for jsonrpc api
10 | * @param {string} topic , topic name
11 | * @param {Function} onPublish , (msg)=>{}
12 | * @param {Function} onSubscribed, ()=>{}
13 | * */
14 | execute(params) {
15 | // let topic = params.topic;
16 | // this._controller.engNode().unsubscribe()
17 | }
18 | }
19 | module.exports = PubSubUnsubscribeAction;
20 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/PubsubPublishAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../common/constants");
2 | const nodeUtils = require("../../../common/utils");
3 |
4 | class PubsubPublishAction {
5 | constructor(controller) {
6 | this._controller = controller;
7 | }
8 |
9 | execute(params) {
10 | const topic = params.topic;
11 | const msgBuffer = Buffer.from(params.message);
12 | this._controller.engNode().broadcast(topic, msgBuffer, () => {
13 | this._controller.logger().debug(`published [${topic}]`);
14 | });
15 | }
16 | }
17 | module.exports = PubsubPublishAction;
18 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/PubsubSubscribeAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../common/constants");
2 | const TOPICS = constants.PUBSUB_TOPICS;
3 |
4 | class PubsubSubscribeAction {
5 | constructor(controller) {
6 | this._controller = controller;
7 | }
8 | /** subscribe to to self ethereum signing key topic - useful for jsonrpc api
9 | * @param {string} topic , topic name
10 | * @param {Function} onPublish , (msg)=>{}
11 | * @param {Function} onSubscribed, ()=>{}
12 | * */
13 | execute(params) {
14 | const topic = params.topic;
15 | const topicHandler = params.onPublish;
16 | const finalHandler = params.onSubscribed;
17 | this._controller.engNode().subscribe([
18 | {
19 | topic: topic,
20 | topic_handler: msg => {
21 | topicHandler(msg);
22 | },
23 | final_handler: () => {
24 | finalHandler();
25 | }
26 | }
27 | ]);
28 | }
29 | }
30 | module.exports = PubsubSubscribeAction;
31 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/connectivity/BootstrapDiscoveredAction.js:
--------------------------------------------------------------------------------
1 | class BootstrapDiscoveredAction {
2 | constructor(controller) {
3 | this._controller = controller;
4 | }
5 |
6 | async execute(params) {
7 | params = params.params;
8 | const otherPeer = params.peer;
9 |
10 | // Connect to a bootstrap only if there are no active connections
11 | if (this._controller.engNode().arePeersConnected()) {
12 | return;
13 | }
14 |
15 | this._controller.logger().info(`trying to connect to discovered bootstrap ${otherPeer.id.toB58String()}`);
16 | const success = await this._controller.engNode().connectToBootstrap(otherPeer);
17 | this._controller.logger().info(`connection to bootstrap succeeded=${success}`);
18 | }
19 | }
20 | module.exports = BootstrapDiscoveredAction;
21 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/connectivity/GetPeers.js:
--------------------------------------------------------------------------------
1 | class GetPeersAction {
2 | constructor(controller) {
3 | this._controller = controller;
4 | }
5 |
6 | execute(params) {
7 | const callback = params.callback;
8 | let length = 0;
9 | let error = null;
10 | try {
11 | length = this._controller.engNode().getConnectedPeers().length;
12 | } catch (err) {
13 | error = err;
14 | }
15 | callback(error, length);
16 | }
17 | }
18 | module.exports = GetPeersAction;
19 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/connectivity/NewPeerAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../common/constants");
2 |
3 | class NewPeerAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 |
8 | execute(params) {
9 | params = params.params;
10 | const callback = params.callback;
11 | const autoInit = this._controller.isAutoInit();
12 | const initRequired = this._controller.canInitWorker();
13 |
14 | // Check if auto init is set and initialization has not done yet
15 | if (autoInit && initRequired) {
16 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.INIT_WORKER, {
17 | callback: callback
18 | });
19 | }
20 | }
21 | }
22 | module.exports = NewPeerAction;
23 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/db/DbRequestAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../common/constants");
2 | const errs = require("../../../../common/errors");
3 | const Envelop = require("../../../../main_controller/channels/Envelop");
4 |
5 | class DbRequestAction {
6 | constructor(controller) {
7 | this._controller = controller;
8 | }
9 | execute(params) {
10 | const onResponse = params.onResponse;
11 | const queryType = params.dbQueryType;
12 | const input = params.input;
13 | if (!this._validateRequest(queryType)) {
14 | onResponse(new errs.TypeErr(`"invalid queryType ${queryType}`));
15 | return;
16 | }
17 | const requestEnvelop = new Envelop(
18 | true,
19 | { type: queryType, input: input },
20 | constants.MAIN_CONTROLLER_NOTIFICATIONS.DbRequest
21 | );
22 | this._controller
23 | .communicator()
24 | .sendAndReceive(requestEnvelop)
25 | .then(responseEnvelop => {
26 | const parsedResponse = responseEnvelop.content();
27 | onResponse(parsedResponse.error, parsedResponse);
28 | });
29 | }
30 | _validateRequest(reqType) {
31 | return reqType in constants.CORE_REQUESTS;
32 | }
33 | }
34 | module.exports = DbRequestAction;
35 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/db/read/GetAllAddrsAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../../common/constants");
2 |
3 | /**
4 | * Get all addresses either from core
5 | * params:
6 | * - onResponse : (err,result)=>{}
7 | * */
8 | class GetAllAddrsAction {
9 | constructor(controller) {
10 | this._controller = controller;
11 | }
12 | execute(params) {
13 | const onResponse = params.onResponse;
14 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.DB_REQUEST, {
15 | dbQueryType: constants.CORE_REQUESTS.GetAllAddrs,
16 | onResponse: (err, result) => {
17 | onResponse(err, result);
18 | }
19 | });
20 | }
21 | }
22 | module.exports = GetAllAddrsAction;
23 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/db/read/GetAllTipsAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../../common/constants");
2 |
3 | /**
4 | This action returns all the tips from core.
5 | * */
6 | class GetAllTipsAction {
7 | constructor(controller) {
8 | this._controller = controller;
9 | }
10 | execute(params) {
11 | const onResult = params.onResponse;
12 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.DB_REQUEST, {
13 | dbQueryType: constants.CORE_REQUESTS.GetAllTips,
14 | onResponse: (err, result) => {
15 | let tips;
16 | if (result && result.result && result.result.tips) {
17 | tips = result.result.tips;
18 | } else {
19 | tips = [];
20 | }
21 | return onResult(err, tips);
22 | }
23 | });
24 | }
25 | asyncExecute(params) {
26 | const action = this;
27 | return new Promise((res, rej) => {
28 | params.onResponse = function(err, tips) {
29 | if (err) rej(err);
30 | else res(tips);
31 | };
32 | action.execute(params);
33 | });
34 | }
35 | }
36 | module.exports = GetAllTipsAction;
37 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/db/read/GetContractCodeAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../../common/constants");
2 | /**
3 | This action returns all the requested deltas from core.
4 | * */
5 | class GetContractCodeAction {
6 | constructor(controller) {
7 | this._controller = controller;
8 | }
9 | execute(params) {
10 | const onResult = params.onResponse;
11 | const queryMsg = params.requestMsg;
12 | // make query
13 | const addr = queryMsg.contractAddress();
14 | const input = addr;
15 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.DB_REQUEST, {
16 | dbQueryType: constants.CORE_REQUESTS.GetContract,
17 | input: input,
18 | onResponse: (err, result) => {
19 | return onResult(err, result);
20 | }
21 | });
22 | }
23 | }
24 | module.exports = GetContractCodeAction;
25 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/db/read/GetDeltasAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../../common/constants");
2 |
3 | /**
4 | This action returns all the requested deltas from core.
5 | * */
6 | class GetDeltasAction {
7 | constructor(controller) {
8 | this._controller = controller;
9 | }
10 | execute(params) {
11 | const onResult = params.onResponse;
12 | const queryMsg = params.requestMsg;
13 | // make query
14 | const addr = queryMsg.contractAddress();
15 | const range = queryMsg.getRange();
16 | const from = range.fromIndex;
17 | const to = range.toIndex;
18 | const input = [{ address: addr, from: from, to: to }];
19 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.DB_REQUEST, {
20 | dbQueryType: constants.CORE_REQUESTS.GetDeltas,
21 | input: input,
22 | onResponse: (err, result) => {
23 | return onResult(err, result);
24 | }
25 | });
26 | }
27 | }
28 | module.exports = GetDeltasAction;
29 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/db/read/GetTipsAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../../common/constants");
2 |
3 | /**
4 | This action returns tips for the requested secret contracts array from core.
5 | * */
6 | class GetTipsAction {
7 | constructor(controller) {
8 | this._controller = controller;
9 | }
10 | execute(params) {
11 | const contractAddresses = params.contractAddresses;
12 | const onResult = params.onResponse;
13 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.DB_REQUEST, {
14 | dbQueryType: constants.CORE_REQUESTS.GetTips,
15 | input: [contractAddresses],
16 | onResponse: (err, result) => {
17 | let tips = [];
18 | if (result && result.result && result.result.tips) {
19 | tips = result.result.tips;
20 | }
21 | return onResult(err, tips);
22 | }
23 | });
24 | }
25 | asyncExecute(params) {
26 | const action = this;
27 | return new Promise((res, rej) => {
28 | params.onResponse = function(err, tips) {
29 | if (err) rej(err);
30 | else res(tips);
31 | };
32 | action.execute(params);
33 | });
34 | }
35 | }
36 | module.exports = GetTipsAction;
37 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/db/write/UpdateDbAction.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This action is responsible for writting to the db of core.
3 | * not directly of course.
4 | * this will write:
5 | * - new contract bytecode
6 | * - new deltas to an existing contract.
7 | * */
8 | const constants = require("../../../../../common/constants");
9 |
10 | class UpdateDbAction {
11 | constructor(controller) {
12 | this._controller = controller;
13 | }
14 | execute(params) {
15 | const msgRes = params.data;
16 | const onFinish = params.callback;
17 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.DB_REQUEST, {
18 | input: msgRes,
19 | dbQueryType: constants.CORE_REQUESTS.UpdateDb,
20 | onResponse: (err, result) => {
21 | let error = err;
22 | if (!error) {
23 | if (result.status !== constants.CORE_RESPONSE_STATUS_CODES.OK) {
24 | if (result.errors) {
25 | error = result.errors;
26 | } else {
27 | error = result.status;
28 | }
29 | }
30 | }
31 | onFinish(error, result);
32 | }
33 | });
34 | }
35 | asyncExecute(params) {
36 | const action = this;
37 | return new Promise((res, rej) => {
38 | if (!params) params = {};
39 | params.callback = function(err, result) {
40 | if (err) rej(err);
41 | else res(result);
42 | };
43 | action.execute(params);
44 | });
45 | }
46 | }
47 | module.exports = UpdateDbAction;
48 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/ethereum/GetWorkerParamsAction.js:
--------------------------------------------------------------------------------
1 | class GetWorkerParamsAction {
2 | constructor(controller) {
3 | this._controller = controller;
4 | }
5 | async execute(params) {
6 | const onResult = params.onResponse;
7 | let err = null;
8 | let workerParams = null;
9 |
10 | try {
11 | workerParams = await this._controller
12 | .ethereum()
13 | .api()
14 | .getSelfWorker();
15 | } catch (e) {
16 | this._controller.logger().error(`[GET_ETH_WORKER_PARAM] error = ${e}`);
17 | err = e;
18 | }
19 | if (onResult) {
20 | onResult(err, workerParams);
21 | }
22 | }
23 | asyncExecute(params) {
24 | const action = this;
25 | return new Promise((res, rej) => {
26 | if (!params) params = {};
27 | params.onResponse = function(err, verificationResult) {
28 | if (err) rej(err);
29 | else res(verificationResult);
30 | };
31 | action.execute(params);
32 | });
33 | }
34 | }
35 | module.exports = GetWorkerParamsAction;
36 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/ethereum/LoginAction.js:
--------------------------------------------------------------------------------
1 | class LoginAction {
2 | constructor(controller) {
3 | this._controller = controller;
4 | }
5 | async execute(params) {
6 | const onResult = params.onResponse;
7 | let loginSuccess = false;
8 | let err = null;
9 | try {
10 | await this._controller
11 | .ethereum()
12 | .api()
13 | .login();
14 | this._controller.logger().info(`[LOGIN] successful login`);
15 | loginSuccess = true;
16 | } catch (e) {
17 | this._controller.logger().error(`[LOGIN] error in login error= ${e}`);
18 | err = e;
19 | }
20 | if (onResult) {
21 | onResult(err, loginSuccess);
22 | }
23 | }
24 | asyncExecute(params) {
25 | const action = this;
26 | return new Promise((res, rej) => {
27 | if (!params) params = {};
28 | params.onResponse = function(err, result) {
29 | if (err) rej(err);
30 | else res(result);
31 | };
32 | action.execute(params);
33 | });
34 | }
35 | }
36 | module.exports = LoginAction;
37 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/ethereum/LogoutAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../common/constants");
2 |
3 | class LogoutAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 | async execute(params) {
8 | const onResult = params.onResponse;
9 | let logoutSuccess = false;
10 | let err = null;
11 |
12 | const api = this._controller.ethereum().api();
13 | try {
14 | const workerAddress = api.getWorkerAddress();
15 | const { status } = await api.getWorker(workerAddress);
16 | if (status === constants.ETHEREUM_WORKER_STATUS.LOGGEDOUT) {
17 | this._controller.logger().info(`[LOGOUT] already logged out`);
18 | } else {
19 | await api.logout();
20 | this._controller.logger().info(`[LOGOUT] successful logout`);
21 | }
22 | logoutSuccess = true;
23 | } catch (e) {
24 | this._controller.logger().error(`[LOGOUT] error in logout error= ${e}`);
25 | err = e;
26 | }
27 | if (onResult) {
28 | onResult(err, logoutSuccess);
29 | }
30 | }
31 | asyncExecute(params) {
32 | const action = this;
33 | return new Promise((res, rej) => {
34 | if (!params) params = {};
35 | params.onResponse = function(err, result) {
36 | if (err) rej(err);
37 | else res(result);
38 | };
39 | action.execute(params);
40 | });
41 | }
42 | }
43 | module.exports = LogoutAction;
44 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/ethereum/RegisterAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../common/constants");
2 |
3 | class RegisterAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 | async execute(params) {
8 | const onResult = params.onResponse;
9 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.REGISTRATION_PARAMS, {
10 | onResponse: async (err, regParams) => {
11 | let success = false;
12 | if (err) {
13 | this._controller.logger().error(`[REGISTER] error= ${err}`);
14 | } else {
15 | const signerAddress = regParams.result.signingKey;
16 | const report = regParams.result.report;
17 | const signature = regParams.result.signature;
18 | try {
19 | await this._controller
20 | .ethereum()
21 | .api()
22 | .register(signerAddress, report, signature);
23 | this._controller.logger().info("[REGISTER] successful registration");
24 | success = true;
25 | } catch (e) {
26 | this._controller.logger().error(`[REGISTER] error= ${e}`);
27 | err = e;
28 | }
29 | }
30 | if (onResult) {
31 | onResult(err, success);
32 | }
33 | }
34 | });
35 | }
36 | asyncExecute(params) {
37 | const action = this;
38 | return new Promise((res, rej) => {
39 | if (!params) params = {};
40 | params.onResponse = function(err, result) {
41 | if (err) rej(err);
42 | else res(result);
43 | };
44 | action.execute(params);
45 | });
46 | }
47 | }
48 | module.exports = RegisterAction;
49 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/ethereum/UnregisterAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../common/constants");
2 |
3 | class UnregisterAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 | async execute(params) {
8 | const onResult = params.onResponse;
9 | let success = false;
10 | let err = null;
11 |
12 | const api = this._controller.ethereum().api();
13 |
14 | try {
15 | const workerAddress = api.getWorkerAddress();
16 | const { status } = await api.getWorker(workerAddress);
17 | if (status === constants.ETHEREUM_WORKER_STATUS.UNREGISTERED) {
18 | this._controller.logger().info(`[UNREGISTER] already unregistered`);
19 | } else {
20 | await api.unregister();
21 | this._controller.logger().info(`[UNREGISTER] successful unregister`);
22 | }
23 |
24 | success = true;
25 | } catch (e) {
26 | this._controller.logger().error(`[UNREGISTER] error in unregister error= ${e}`);
27 | err = e;
28 | }
29 | if (onResult) {
30 | onResult(err, success);
31 | }
32 | }
33 | asyncExecute(params) {
34 | const action = this;
35 | return new Promise((res, rej) => {
36 | if (!params) params = {};
37 | params.onResponse = function(err, result) {
38 | if (err) rej(err);
39 | else res(result);
40 | };
41 | action.execute(params);
42 | });
43 | }
44 | }
45 | module.exports = UnregisterAction;
46 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/proxy/GetStatusProxyAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../common/constants");
2 | const Envelop = require("../../../../main_controller/channels/Envelop");
3 | /**
4 | * This action takes a taskId and checks if the result + status exists locally.
5 | * if true: returns back the envelop
6 | * else:
7 | * ROUTE_BLOCKING_RPC (i.e goes to the network and looks for the worker)
8 | * */
9 | class GetStatusProxyAction {
10 | constructor(controller) {
11 | this._controller = controller;
12 | }
13 | async execute(requestEnvelop) {
14 | let taskId = requestEnvelop.content().taskId;
15 | try {
16 | let result = await this._controller.asyncExecCmd(constants.NODE_NOTIFICATIONS.GET_TASK_RESULT, {
17 | taskId: taskId
18 | });
19 | const responseEnvelop = new Envelop(
20 | requestEnvelop.id(),
21 | { result: result.getStatus(), output: result.getOutput() },
22 | requestEnvelop.type()
23 | );
24 | this._controller.communicator().send(responseEnvelop);
25 | } catch (e) {
26 | this._controller.logger().error(e);
27 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.ROUTE_BLOCKING_RPC, requestEnvelop);
28 | }
29 | }
30 | }
31 | module.exports = GetStatusProxyAction;
32 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/proxy/ProxyDispatcherAction.js:
--------------------------------------------------------------------------------
1 | /**
2 | * performed by the gateway side.
3 | * this action dispatches
4 | * */
5 |
6 | const constants = require("../../../../common/constants");
7 | const utils = require("../../../../common/utils");
8 | const Envelop = require("../../../../main_controller/channels/Envelop");
9 |
10 | class ProxyDispatcherAction {
11 | constructor(controller) {
12 | this._controller = controller;
13 | }
14 | async execute(requestEnvelop) {
15 | const type = requestEnvelop.content().type;
16 | let theAction = null;
17 | switch (type) {
18 | case constants.CORE_REQUESTS.NewTaskEncryptionKey:
19 | theAction = constants.NODE_NOTIFICATIONS.ROUTE_BLOCKING_RPC;
20 | const workerSignKey = requestEnvelop.content().workerSignKey;
21 | const sequence = requestEnvelop.content().id;
22 | const selfId = this._controller.engNode().getSelfIdB58Str();
23 | requestEnvelop.content().targetTopic = selfId + workerSignKey + sequence;
24 | break;
25 | case constants.NODE_NOTIFICATIONS.GET_TASK_STATUS:
26 | theAction = constants.NODE_NOTIFICATIONS.DISPATCH_STATUS_REQ_RPC;
27 | const taskId = requestEnvelop.content().taskId;
28 | const workerAddr = requestEnvelop.content().workerAddress;
29 | requestEnvelop.content().targetTopic = taskId + workerAddr;
30 | requestEnvelop.content().workerSignKey = workerAddr;
31 | if (!requestEnvelop.content().id) {
32 | requestEnvelop.content().id = taskId;
33 | }
34 | break;
35 | case constants.CORE_REQUESTS.DeploySecretContract:
36 | try {
37 | // translate from base64 to byte array
38 | const preCodeBufferGzip = Buffer.from(requestEnvelop.content().request.preCode, "base64");
39 | // unzip the preCode
40 | const preCodeBuffer = await utils.gunzip(preCodeBufferGzip);
41 | const preCodeByteArray = [...preCodeBuffer];
42 | requestEnvelop.content().request.preCode = preCodeByteArray;
43 | } catch (e) {
44 | this._controller
45 | .logger()
46 | .info(`[PROXY_DISPATCH] an exception occurred while trying to unpack DeploySecretContract RPC ${e}`);
47 | return;
48 | }
49 | case constants.CORE_REQUESTS.ComputeTask:
50 | theAction = constants.NODE_NOTIFICATIONS.ROUTE_NON_BLOCK_RPC;
51 | break;
52 | case constants.NODE_NOTIFICATIONS.GET_TASK_RESULT:
53 | this._getTaskResult(type, requestEnvelop);
54 | break;
55 | }
56 | if (theAction) {
57 | this._controller.logger().debug("[PROXY_DISPATCH] sending dispatched rpc request");
58 | this._controller.execCmd(theAction, requestEnvelop);
59 | }
60 | }
61 | async _getTaskResult(type, requestEnvelop) {
62 | let result = null;
63 | try {
64 | result = await this._controller.asyncExecCmd(type, {
65 | taskId: requestEnvelop.content().taskId
66 | });
67 | if (result) {
68 | result = result.toDbJson();
69 | } else {
70 | this._controller.logger().info(`[PROXY_DISPATCH] received an empty result`);
71 | }
72 | } catch (e) {
73 | this._controller.logger().info(`[PROXY_DISPATCH] problem in getting result ${e}`);
74 | } finally {
75 | const responseEnvelop = new Envelop(requestEnvelop.id(), { result: result }, requestEnvelop.type());
76 | this._controller.communicator().send(responseEnvelop);
77 | }
78 | }
79 | }
80 | module.exports = ProxyDispatcherAction;
81 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/proxy/RouteRpcBlockingAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../common/constants");
2 | const EncoderUtil = require("../../../../common/EncoderUtil");
3 | const Envelop = require("../../../../main_controller/channels/Envelop");
4 |
5 | class RouteRpcBlockingAction {
6 | constructor(controller) {
7 | this._controller = controller;
8 | }
9 | /**
10 | * expects a targetTopic and id in the envelop.content()
11 | * targetTopic : the result topic will be published to
12 | * workerSignKey : the target topic for the request
13 | * */
14 | execute(requestEnvelop) {
15 | const request = requestEnvelop.content();
16 | const sequence = requestEnvelop.content().id;
17 | const targetTopic = requestEnvelop.content().targetTopic;
18 | const workerSignKey = requestEnvelop.content().workerSignKey;
19 | const reqType = requestEnvelop.content().type;
20 |
21 | if (!targetTopic || !sequence || !workerSignKey) {
22 | this._sendResponseEnvelope(requestEnvelop, false, "error no sequence/targetTopic/signKey");
23 | return;
24 | }
25 |
26 | const routedMessage = EncoderUtil.encode({
27 | type: reqType,
28 | request: request,
29 | sequence: sequence,
30 | targetTopic: targetTopic
31 | });
32 | if (!routedMessage) {
33 | this._sendResponseEnvelope(requestEnvelop, false, "error in encoding routed message");
34 | return;
35 | }
36 |
37 | // onPublish callback
38 | const onPublish = msg => {
39 | // once the result from the worker arrives
40 | const data = EncoderUtil.decode(msg.data);
41 | if (!data) {
42 | this._sendResponseEnvelope(requestEnvelop, false, "error in decoding response message");
43 | } else {
44 | this._sendResponseEnvelope(requestEnvelop, data.result, null);
45 | }
46 | // TODO:: possible unsubscribe depends what the reqs are it might not be default maybe reuse the topic
47 | };
48 | // onSubscribed callback
49 | const onSubscribed = () => {
50 | console.log("[rpc] subscribed to target topic = " + targetTopic);
51 | // publish the actual request
52 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.PUBSUB_PUB, {
53 | topic: workerSignKey,
54 | message: routedMessage
55 | });
56 | };
57 |
58 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.PUBSUB_SUB, {
59 | topic: targetTopic,
60 | onPublish: onPublish,
61 | onSubscribed: onSubscribed
62 | });
63 | }
64 |
65 | _sendResponseEnvelope(requestEnvelop, result, error) {
66 | const env = new Envelop(requestEnvelop.id(), { result: result, error: error }, requestEnvelop.type());
67 | this._controller.communicator().send(env);
68 | }
69 | }
70 | module.exports = RouteRpcBlockingAction;
71 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/proxy/RouteRpcNonBlockingAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../common/constants");
2 | const Envelop = require("../../../../main_controller/channels/Envelop");
3 | const EncoderUtil = require("../../../../common/EncoderUtil");
4 |
5 | class RouteRpcNonBlockingAction {
6 | constructor(controller) {
7 | this._controller = controller;
8 | }
9 | execute(requestEnvelop) {
10 | const targetTopic = requestEnvelop.content().request.workerAddress;
11 | const request = requestEnvelop.content().request;
12 | const type = requestEnvelop.content().type;
13 |
14 | // validate topic indicated
15 | if (!targetTopic || !request) {
16 | this._sendResponseEnvelope(requestEnvelop, { sent: false }, "error no targetTopic/request");
17 | return;
18 | }
19 | // encode routed msg
20 | const routedMessage = EncoderUtil.encode({
21 | type: type,
22 | request: request
23 | });
24 | if (!routedMessage) {
25 | this._sendResponseEnvelope(requestEnvelop, { sent: false }, "error in encoding routed message");
26 | return;
27 | }
28 |
29 | // send the request
30 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.PUBSUB_PUB, {
31 | topic: targetTopic,
32 | message: routedMessage
33 | });
34 | // return jsonrpc response ack
35 | this._sendResponseEnvelope(requestEnvelop, { sent: true }, null);
36 | }
37 |
38 | _sendResponseEnvelope(requestEnvelop, result, error) {
39 | const env = new Envelop(requestEnvelop.id(), { result: result, error: error }, requestEnvelop.type());
40 | this._controller.communicator().send(env);
41 | }
42 | }
43 | module.exports = RouteRpcNonBlockingAction;
44 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/sync/AnnounceContentAction.js:
--------------------------------------------------------------------------------
1 | const errors = require("../../../../common/errors");
2 |
3 | class AnnounceContentAction {
4 | constructor(controller) {
5 | this._controller = controller;
6 | }
7 | async execute(params) {
8 | const onResponse = params.onResponse;
9 | let engCids = params.engCids;
10 | if (!engCids || !engCids.length) {
11 | const msg = `[AnnounceContent] ${engCids} is not list of EngCid's`;
12 | this._controller.logger().error(msg);
13 | return onResponse(new errors.TypeErr(msg));
14 | }
15 | try {
16 | let failedCids = await this._controller.provider().asyncProvideContentsBatch(engCids);
17 | if (Array.isArray(failedCids) && failedCids.length) {
18 | if (failedCids.length === engCids.length) {
19 | const error = `[AnnounceContent] content announce failed`;
20 | this._controller.logger().error(error);
21 | return onResponse(error);
22 | }
23 | this._controller
24 | .logger()
25 | .debug(`[AnnounceContent] announced = ${engCids.length - failedCids.length} out of ${engCids.length}`);
26 | } else {
27 | this._controller.logger().debug(`[AnnounceContent] success announcing content`);
28 | }
29 | return onResponse(null, failedCids);
30 | } catch (e) {
31 | this._controller.logger().error(`[AnnounceContent] can't announce: ${e}`);
32 | return onResponse(e);
33 | }
34 | }
35 | asyncExecute(params) {
36 | const action = this;
37 | return new Promise((res, rej) => {
38 | params.onResponse = function(err, failedCids) {
39 | if (err) rej(err);
40 | else res(failedCids);
41 | };
42 | action.execute(params);
43 | });
44 | }
45 | }
46 | module.exports = AnnounceContentAction;
47 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/sync/AnnounceLocalStateAction.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../../../common/constants");
2 | const EngCid = require("../../../../common/EngCID");
3 | /**
4 | * This Action announces to the network about it's local state
5 | * This should be called once the node is synched with the network and has all the deltas and contracts.
6 | * //TODO:: add flag to check if and only if NODE_IS_FULLY_SYNCED then allow otherwise dismiss the request
7 | * */
8 | class AnnounceLocalStateAction {
9 | constructor(controller) {
10 | this._controller = controller;
11 | }
12 | execute(params) {
13 | const onResponse = params.onResponse;
14 | let isEngCid = params.isEngCid;
15 |
16 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.GET_ALL_ADDRS, {
17 | onResponse: (err, allAddrsResponse) => {
18 | /**
19 | * do the announcement
20 | * */
21 | let parsedEngCids = [];
22 | for (const address of allAddrsResponse.result.addresses) {
23 | const ecid = EngCid.createFromSCAddress(address);
24 | if (ecid) {
25 | parsedEngCids.push(ecid);
26 | } else {
27 | this._controller.logger().error(`error converting address ${address} to ecid !`);
28 | }
29 | }
30 | isEngCid = true;
31 | this._controller.provider().provideContentsBatch(parsedEngCids, isEngCid, failedCids => {
32 | return onResponse(null, parsedEngCids);
33 | });
34 | }
35 | });
36 | }
37 |
38 | asyncExecute(params) {
39 | const action = this;
40 | return new Promise((resolve, reject) => {
41 | params.callback = function(status, result) {
42 | resolve({ status: status, result: result });
43 | };
44 | action.execute(params);
45 | });
46 | }
47 | }
48 | module.exports = AnnounceLocalStateAction;
49 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/sync/FindContentProviderAction.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Find content providers to provide data
3 | * Takes list of hashes -> turns them into cid's
4 | * calls next(result)
5 | * */
6 | class FindContentProviderAction {
7 | constructor(controller) {
8 | this._controller = controller;
9 | }
10 | execute(params) {
11 | const descriptorsList = params.descriptorsList;
12 | const next = params.next;
13 | const isEngCid = params.isEngCid;
14 | this._controller.receiver().findProvidersBatch(descriptorsList, isEngCid, findProviderResult => {
15 | // TODO:: add error param to the callback.
16 | next(null, findProviderResult);
17 | });
18 | }
19 | asyncExecute(params) {
20 | const action = this;
21 | return new Promise((resolve, reject) => {
22 | if (!params) {
23 | params = {};
24 | }
25 | params.next = function(err, data) {
26 | if (err) reject(err);
27 | else resolve(data);
28 | };
29 | action.execute(params);
30 | });
31 | }
32 | }
33 | module.exports = FindContentProviderAction;
34 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/sync/GetLocalTipsOfRemote.js:
--------------------------------------------------------------------------------
1 | const errors = require("../../../../common/errors");
2 | /**
3 | * Find content providers to provide data
4 | * Takes list of hashes -> turns them into cid's
5 | * calls next(result)
6 | * */
7 | class GetLocalTipsOfRemote {
8 | constructor(controller) {
9 | this._controller = controller;
10 | }
11 | async execute(params) {
12 | let peerB58Id = params.peerB58Id;
13 | if (!peerB58Id) {
14 | return null;
15 | }
16 | try {
17 | let peerInfo = await this._controller.engNode().lookUpPeer(peerB58Id);
18 | if (!peerInfo) {
19 | throw new errors.P2PErr(`no such peer ${b58Id}`);
20 | }
21 | let remoteTips = await this._controller.engNode().getLocalStateOfRemote(peerInfo);
22 | return remoteTips;
23 | } catch (e) {
24 | this._controller.logger().error(`GetLocalTipsOfRemote Action ${e}`);
25 | return null;
26 | }
27 | }
28 | }
29 | module.exports = GetLocalTipsOfRemote;
30 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/sync/IdentifyMissingStatesAction.js:
--------------------------------------------------------------------------------
1 | const StateSync = require("../../../../ethereum/StateSync");
2 | const constants = require("../../../../common/constants");
3 | const errs = require("../../../../common/errors");
4 | const NODE_NOTIY = constants.NODE_NOTIFICATIONS;
5 |
6 | /**
7 | * This action is the first step to sync
8 | * this identifies the missing state the worker needs.
9 | * - it will read from core.
10 | * - get the local tips
11 | * - get remote tips
12 | * - parse them into a format class "MissingStatesMap"
13 | * - and return the result to the caller.
14 | * @return {JSON} res:
15 | * missingList - missing states [{address, deltas : [deltaHash, index]}].
16 | * In case the entire contract is missing, the bytecodeHash is returned as well:
17 | * [{address, bytecodeHash , deltas : [deltaHash, index]}]
18 | * excessList - excessive states [{address, remoteTip].
19 | * In case the entire contract is excessive, the remoteTip field is set to -1
20 | * */
21 | class IdentifyMissingStatesAction {
22 | constructor(controller) {
23 | this._controller = controller;
24 | }
25 | async execute(params) {
26 | const callback = params.onResponse;
27 | try {
28 | // LOCAL TIPS : {type,id,tips: [{address,key,delta},...]}
29 | const localTips = await this._controller.asyncExecCmd(NODE_NOTIY.GET_ALL_TIPS, {});
30 | if (!this._controller.hasEthereum()) {
31 | const error = new errs.EthereumErr(`[IDENTIFY_MISSING_STATES] failure, no ethereum!`);
32 | return callback(error);
33 | }
34 | StateSync.compareLocalStateToRemote(this._controller.ethereum().api(), localTips)
35 | .then(res => {
36 | callback(null, res);
37 | })
38 | .catch(err => callback(err));
39 | } catch (err) {
40 | return callback(err);
41 | }
42 | }
43 |
44 | asyncExecute(params) {
45 | const action = this;
46 | return new Promise((resolve, reject) => {
47 | if (!params) {
48 | params = {};
49 | }
50 | params.onResponse = function(err, data) {
51 | if (err) reject(err);
52 | else resolve(data);
53 | };
54 | action.execute(params);
55 | });
56 | }
57 | }
58 | module.exports = IdentifyMissingStatesAction;
59 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/sync/ProvideSyncStateAction.js:
--------------------------------------------------------------------------------
1 | class ProvideSyncStateAction {
2 | constructor(controller) {
3 | this._controller = controller;
4 | }
5 | execute(params) {
6 | const provider = this._controller.provider();
7 | const connectionStream = params.params.connection;
8 | provider.startStateSyncResponse(connectionStream);
9 | }
10 | }
11 | module.exports = ProvideSyncStateAction;
12 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/sync/TryReceiveAllAction.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This can fail.
3 | * Given an input:
4 | * - Missing deltas
5 | * - CID's and ProviderList for EACH CID (FindProviderResult.js)
6 | * Fetch from the providers all the bytecode/deltas
7 | * */
8 | const waterfall = require("async/waterfall");
9 | const errors = require("../../../../common/errors");
10 | class TryReceiveAllAction {
11 | constructor(controller) {
12 | this._controller = controller;
13 | }
14 | /**
15 | * @param {JSON} params : {
16 | * - findProvidersResult
17 | * - missingStates
18 | * - onFinish
19 | * }
20 | * */
21 | execute(params) {
22 | const allMissingDataList = params.allMissingDataList;
23 | const remoteMissingStatesMap = params.remoteMissingStatesMap;
24 | const onFinish = params.onFinish;
25 | const receiver = this._controller.receiver();
26 |
27 | if (allMissingDataList.length === 0) {
28 | this._controller.logger().info(`[TRY_RECEIVE_ALL] No missing data`);
29 | return onFinish(null);
30 | }
31 |
32 | const jobs = [];
33 | const firstJob = allMissingDataList[0];
34 | // pass the missingStateList to the receiver
35 | receiver.setRemoteMissingStatesMap(remoteMissingStatesMap);
36 | // init the first job
37 | jobs.push(cb => {
38 | receiver.trySyncReceive(firstJob.providers, firstJob.requestMessages, (err, isDone, resultList) => {
39 | if (err) {
40 | return cb(err);
41 | } else {
42 | const allResults = [];
43 | allResults.push({
44 | success: isDone,
45 | resultList: resultList,
46 | error: err
47 | });
48 | return cb(null, allResults);
49 | }
50 | });
51 | });
52 | // init the rest of the jobs
53 | for (let i = 1; i < allMissingDataList.length; ++i) {
54 | const providers = allMissingDataList[i].providers;
55 | const requestMessages = allMissingDataList[i].requestMessages;
56 | jobs.push((allResults, cb) => {
57 | receiver.trySyncReceive(providers, requestMessages, (err, isDone, resultList) => {
58 | if (err) {
59 | return cb(err);
60 | } else {
61 | allResults.push({
62 | success: isDone,
63 | resultList: resultList,
64 | error: err
65 | });
66 | return cb(null, allResults);
67 | }
68 | });
69 | });
70 | }
71 | // execute all the jobs
72 | waterfall(jobs, (err, allResults) => {
73 | onFinish(err, allResults);
74 | });
75 | }
76 | asyncExecute(params) {
77 | const action = this;
78 | return new Promise((resolve, reject) => {
79 | if (!params) {
80 | params = {};
81 | }
82 | params.onFinish = function(err, data) {
83 | if (err) reject(err);
84 | else resolve(data);
85 | };
86 | action.execute(params);
87 | });
88 | }
89 | }
90 | module.exports = TryReceiveAllAction;
91 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/tasks/GetResultAction.js:
--------------------------------------------------------------------------------
1 | class GetResultAction {
2 | constructor(controller) {
3 | this._controller = controller;
4 | }
5 | async execute(params) {
6 | let taskId = params.taskId;
7 | let task = await this._controller.taskManager().asyncGetTask(taskId);
8 | return task.getResult();
9 | }
10 | asyncExecute(params) {
11 | return this.execute(params);
12 | }
13 | }
14 | module.exports = GetResultAction;
15 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/tasks/HandleVerifiedTaskAction.js:
--------------------------------------------------------------------------------
1 | /**
2 | * this action is called once a task is verified and now needs to be executed.
3 | * it checks whether PTT in progress, if so the task execution is delayed. If not, the task execution starts immediately.
4 | * */
5 | const constants = require("../../../../common/constants");
6 |
7 | class HandleVerifiedTaskAction {
8 | constructor(controller) {
9 | this._controller = controller;
10 | }
11 | async execute(params) {
12 | const task = params.task;
13 |
14 | const executeTaskCallback = () => {
15 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.EXEC_TASK, {
16 | task: task
17 | });
18 | };
19 |
20 | // First check if we are in the middle of PTT
21 | // if so, schedule the task execution to after it is done
22 | if (this._controller.principal().isInPTT()) {
23 | this._controller.principal().once(constants.PTT_END_EVENT, executeTaskCallback);
24 | }
25 | // otherwise, execute task now
26 | else {
27 | executeTaskCallback();
28 | }
29 | }
30 | }
31 | module.exports = HandleVerifiedTaskAction;
32 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/tasks/PublishTaskResultAction.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Once the TaskManager emits FINISH_TASK
3 | * this action:
4 | * - publish the result to the results topic
5 | * - publish the result back to etherum
6 | * */
7 | const constants = require("../../../../common/constants");
8 | const DeployTask = require("../../../tasks/DeployTask");
9 | const EngCid = require("../../../../common/EngCID");
10 |
11 | class PublishTaskResultAction {
12 | constructor(controller) {
13 | this._controller = controller;
14 | }
15 | async execute(params) {
16 | const task = params.task;
17 | let taskType;
18 | let err = null;
19 |
20 | if (task.isSuccess()) {
21 | taskType = task.getTaskType();
22 | } else {
23 | taskType = constants.CORE_REQUESTS.FailedTask;
24 | }
25 |
26 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.PUBSUB_PUB, {
27 | topic: constants.PUBSUB_TOPICS.TASK_RESULTS,
28 | message: JSON.stringify({
29 | contractAddress: task.getContractAddr(),
30 | result: task.getResult().toDbJson(),
31 | type: taskType
32 | })
33 | });
34 |
35 | // commit to Ethereum
36 | if (this._controller.hasEthereum()) {
37 | err = await this._controller.asyncExecCmd(constants.NODE_NOTIFICATIONS.COMMIT_RECEIPT, {
38 | task: task
39 | });
40 | if (err) {
41 | this._controller.logger().info(`[PUBLISH_ANNOUNCE_TASK] error occurred in task ${task.getTaskId()} commit`);
42 | }
43 | }
44 |
45 | // announce as provider if its deployment and successful and no error occurred in task's commit
46 | if (task instanceof DeployTask && task.getResult().isSuccess() && !err) {
47 | //
48 | let ecid = EngCid.createFromSCAddress(task.getContractAddr());
49 | if (ecid) {
50 | try {
51 | await this._controller.asyncExecCmd(constants.NODE_NOTIFICATIONS.ANNOUNCE_ENG_CIDS, { engCids: [ecid] });
52 | } catch (e) {
53 | this._controller.logger().debug(`[PUBLISH_ANNOUNCE_TASK] cant publish ecid ${e}`);
54 | }
55 | } else {
56 | this._controller
57 | .logger()
58 | .error(`[PUBLISH_ANNOUNCE_TASK] cant publish ${task.getContractAddr()} - ecid is null`);
59 | }
60 | }
61 | }
62 | }
63 | module.exports = PublishTaskResultAction;
64 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/tasks/StartTaskExecutionAction.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This action takes a raw message (usually jsonrpc or self compute)
3 | * - turns it into a Task object
4 | * - sends to TaskManager
5 | * */
6 | const ComputeTask = require("../../../tasks/ComputeTask");
7 | const DeployTask = require("../../../tasks/DeployTask");
8 | const taskTypes = require("../../../../common/constants").CORE_REQUESTS;
9 |
10 | class StartTaskExecutionAction {
11 | constructor(controller) {
12 | this._controller = controller;
13 | }
14 | execute(params) {
15 | const type = params.type;
16 | const request = params.request;
17 | const onResponse = params.onResponse;
18 | let task = null;
19 |
20 | // The following parameters are being overwritten in the VerifyNewTaskAction
21 | request.gasLimit = 0;
22 | request.blockNumber = 0;
23 |
24 | switch (type) {
25 | case taskTypes.DeploySecretContract:
26 | request.taskId = request.contractAddress;
27 | task = DeployTask.buildTask(request);
28 | break;
29 | case taskTypes.ComputeTask:
30 | task = ComputeTask.buildTask(request);
31 | break;
32 | }
33 | if (task) {
34 | this._controller.taskManager().addTaskUnverified(task);
35 | }
36 | if (onResponse) {
37 | onResponse(null);
38 | }
39 | }
40 | asyncExecute(params) {
41 | const action = this;
42 | return new Promise((res, rej) => {
43 | params.onResponse = function(err, verificationResult) {
44 | if (err) rej(err);
45 | else res(verificationResult);
46 | };
47 | action.execute(params);
48 | });
49 | }
50 | }
51 | module.exports = StartTaskExecutionAction;
52 |
--------------------------------------------------------------------------------
/src/worker/controller/actions/tasks/VerifyNewTaskAction.js:
--------------------------------------------------------------------------------
1 | /**
2 | * verify a task
3 | * */
4 | const constants = require("../../../../common/constants");
5 | const ethUtils = require("../../../../common/utils");
6 |
7 | class VerifyNewTaskAction {
8 | constructor(controller) {
9 | this._controller = controller;
10 | }
11 | async execute(params) {
12 | let onResult = params.onResponse;
13 | const unverifiedTask = params.task;
14 | this._controller.execCmd(constants.NODE_NOTIFICATIONS.REGISTRATION_PARAMS, {
15 | onResponse: async (err, regParams) => {
16 | // TODO: remove this default!!!!
17 | let isVerified = true;
18 | if (this._controller.hasEthereum()) {
19 | isVerified = false;
20 | try {
21 | const currentBlockNumber = await ethUtils.getEthereumBlockNumber(
22 | this._controller
23 | .ethereum()
24 | .api()
25 | .w3()
26 | );
27 | let res = await this._controller
28 | .ethereum()
29 | .verifier()
30 | .verifyTaskCreation(unverifiedTask, currentBlockNumber, regParams.result.signingKey);
31 | if (res.error) {
32 | this._controller
33 | .logger()
34 | .info(`[VERIFY_NEW_TASK] error in verification of task ${unverifiedTask.getTaskId()}: ${res.error}`);
35 | } else if (res.isVerified) {
36 | unverifiedTask.setGasLimit(res.gasLimit);
37 | unverifiedTask.setBlockNumber(res.blockNumber);
38 | this._controller
39 | .logger()
40 | .debug(`[VERIFY_NEW_TASK] successful verification of task ${unverifiedTask.getTaskId()}`);
41 | isVerified = true;
42 | }
43 | } catch (err) {
44 | this._controller
45 | .logger()
46 | .error(
47 | `[VERIFY_NEW_TASK] an exception occurred while trying to verify task ${unverifiedTask.getTaskId()} = ${err}`
48 | );
49 | }
50 | }
51 | await this._controller.taskManager().asyncOnVerifyTask(unverifiedTask.getTaskId(), isVerified);
52 | if (onResult) {
53 | onResult(null, isVerified);
54 | }
55 | }
56 | });
57 | }
58 |
59 | asyncExecute(params) {
60 | const action = this;
61 | return new Promise((res, rej) => {
62 | params.onResponse = function(err, verificationResult) {
63 | if (err) rej(err);
64 | else res(verificationResult);
65 | };
66 | action.execute(params);
67 | });
68 | }
69 | }
70 | module.exports = VerifyNewTaskAction;
71 |
72 | // let c = nodeController;
73 | // let isVerified= await c.asyncExecCmd('verify aeubesiuhf', {task: Task});
74 |
--------------------------------------------------------------------------------
/src/worker/handlers/ManagementServer.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const http = require("http");
3 | const EventEmitter = require("events").EventEmitter;
4 | const constants = require("../../common/constants");
5 | const WEB_SERVER_CONSTANTS = constants.WEB_SERVER_CONSTANTS;
6 | const GET_PEERS_CONST = constants.NODE_NOTIFICATIONS.GET_PEERS;
7 |
8 | const mgmtActions = [
9 | constants.NODE_NOTIFICATIONS.REGISTER,
10 | constants.NODE_NOTIFICATIONS.LOGIN,
11 | constants.NODE_NOTIFICATIONS.LOGOUT,
12 | constants.NODE_NOTIFICATIONS.UNREGISTER
13 | ];
14 |
15 | class ManagementServer extends EventEmitter {
16 | constructor(config, logger) {
17 | super();
18 | if (!config.hasOwnProperty("mgmtBase")) {
19 | throw new Error("Webserver config doesn't contain 'mgmtBase' option required");
20 | }
21 | this._mgmtPort = Object.prototype.hasOwnProperty.call(config["mgmtBase"], "port")
22 | ? config["mgmtBase"].port
23 | : WEB_SERVER_CONSTANTS.MGMT.port;
24 | this._mgmtUrl = Object.prototype.hasOwnProperty.call(config["mgmtBase"], "url")
25 | ? config["mgmtBase"].url
26 | : WEB_SERVER_CONSTANTS.MGMT.url;
27 |
28 | this._logger = logger;
29 | this._app = express();
30 | this._server = null;
31 | }
32 |
33 | start() {
34 | this._server = http.createServer(this._app);
35 | this._server.listen(this._mgmtPort);
36 | mgmtActions.forEach(item => {
37 | this._app.get(`${this._mgmtUrl}/${item}`, this.performAction.bind(this, item));
38 | });
39 | this._app.get(`${this._mgmtUrl}/connections`, this.getPeers.bind(this));
40 | this._logger.debug(`listening on port ${this._mgmtPort} for management on URL ${this._mgmtUrl}`);
41 | }
42 |
43 | stop() {
44 | if (this._server) {
45 | this._server.close();
46 | }
47 | }
48 | /**
49 | * Notify observer (Some controller subscribed)
50 | * @param {JSON} params, MUST CONTAIN notification field
51 | */
52 | notify(params) {
53 | this.emit("notify", params);
54 | }
55 | async getPeers(req, res, next) {
56 | this.notify({
57 | notification: GET_PEERS_CONST,
58 | callback: (err, result) => {
59 | if (Number.isInteger(result)) {
60 | res.json(result.toString());
61 | } else {
62 | next(WEB_SERVER_CONSTANTS.error_code);
63 | }
64 | }
65 | });
66 | }
67 |
68 | async performAction(notification, req, res, next) {
69 | this._logger.info(`Management Server: Got notification for ${notification}`);
70 | this.notify({
71 | notification: notification,
72 | onResponse: (err, result) => {
73 | if (result) {
74 | res.send(result);
75 | } else {
76 | next(WEB_SERVER_CONSTANTS.error_code);
77 | }
78 | }
79 | });
80 | }
81 | }
82 |
83 | module.exports = ManagementServer;
84 |
--------------------------------------------------------------------------------
/src/worker/handlers/PrincipalNode.js:
--------------------------------------------------------------------------------
1 | const jayson = require("jayson");
2 | const retry = require("retry");
3 | const EventEmitter = require("events").EventEmitter;
4 |
5 | const constants = require("../../common/constants");
6 | const MsgPrincipal = require("../../policy/p2p_messages/principal_messages");
7 | const PRINCIPAL_CONSTANTS = constants.PRINCIPAL_NODE;
8 |
9 | class PrincipalNode extends EventEmitter {
10 | constructor(config, logger) {
11 | super();
12 |
13 | if (config && config.uri) {
14 | this._uri = config.uri;
15 | } else {
16 | this._uri = PRINCIPAL_CONSTANTS.uri;
17 | }
18 |
19 | this._logger = logger;
20 | this._client = jayson.client.http(this._uri);
21 | this._pttInProgress = false;
22 | }
23 |
24 | startPTT() {
25 | if (this._pttInProgress) {
26 | this._logger.error("PTT is already in progress, cannot initiate a new one");
27 | return false;
28 | }
29 | this._pttInProgress = true;
30 | return true;
31 | }
32 |
33 | onPTTEnd() {
34 | this._pttInProgress = false;
35 | this.emit(constants.PTT_END_EVENT);
36 | }
37 |
38 | isInPTT() {
39 | return this._pttInProgress;
40 | }
41 |
42 | async getStateKeys(msg) {
43 | return new Promise((resolve, reject) => {
44 | if (!(msg instanceof MsgPrincipal)) {
45 | // TODO: Changed to type error from common/errors.
46 | reject(new Error("getStateKeys accepts only object of type MsgPrincipal"));
47 | }
48 |
49 | // TODO: adjust config params and not use defaults
50 | let operation = retry.operation(PRINCIPAL_CONSTANTS.retryOptions);
51 | operation.attempt(currentAttempt => {
52 | this._client.request("getStateKeys", msg.toJson(), (err, response) => {
53 | if (this._logger) {
54 | this._logger.debug("Connecting to principal node: " + this._uri);
55 | }
56 | // Check if there was an error and the operation can be retried
57 | if (
58 | (err ||
59 | (response.error &&
60 | response.error.code &&
61 | response.error.code === PRINCIPAL_CONSTANTS.EPOCH_STATE_TRANSITION_ERROR_CODE)) &&
62 | operation.retry(true)
63 | ) {
64 | const error = err || PRINCIPAL_CONSTANTS.EPOCH_STATE_TRANSITION_ERROR_CODE;
65 | this._logger.debug("Error received from KM, will retry. Error code =" + error);
66 | return;
67 | }
68 |
69 | // Check if there was an error (after the retries have done) and reject
70 | if (err) return reject(err);
71 |
72 | // Check the response and reject/resolve accordingly
73 | if (response.error) return reject(response.error);
74 | resolve(response.result);
75 | });
76 | });
77 | });
78 | }
79 | }
80 |
81 | module.exports = PrincipalNode;
82 |
--------------------------------------------------------------------------------
/src/worker/handlers/WebServer.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const http = require("http");
3 | const EventEmitter = require("events").EventEmitter;
4 | const constants = require("../../common/constants");
5 | const WEB_SERVER_CONSTANTS = constants.WEB_SERVER_CONSTANTS;
6 |
7 | class WebServer extends EventEmitter {
8 | constructor(config, logger) {
9 | super();
10 |
11 | if (config && config.port) {
12 | this._port = config.port;
13 | } else {
14 | this._port = WEB_SERVER_CONSTANTS.port;
15 | }
16 | if (config.healthCheck && config.healthCheck.url) {
17 | this._healthCheckUrl = config.healthCheck.url;
18 | } else {
19 | this._healthCheckUrl = WEB_SERVER_CONSTANTS.health.url;
20 | }
21 | if (config.status && config.status.url) {
22 | this._statusUrl = config.status.url;
23 | } else {
24 | this._statusUrl = WEB_SERVER_CONSTANTS.status.url;
25 | }
26 | this._logger = logger;
27 | this._app = express();
28 | this._server = null;
29 | }
30 |
31 | start() {
32 | this._server = http.createServer(this._app);
33 | this._server.listen(this._port);
34 | this._app.get(this._healthCheckUrl, this.performHealthCheck.bind(this));
35 | this._app.get(this._statusUrl, this.getStatus.bind(this));
36 | this._logger.debug(
37 | `listening on port ${this._port} for health check on URL ${this._healthCheckUrl} and status queries on URL ${this._statusUrl}`
38 | );
39 | }
40 |
41 | stop() {
42 | if (this._server) {
43 | this._server.close();
44 | }
45 | }
46 | /**
47 | * Notify observer (Some controller subscribed)
48 | * @param {JSON} params, MUST CONTAIN notification field
49 | */
50 | notify(params) {
51 | this.emit("notify", params);
52 | }
53 |
54 | async performHealthCheck(req, res, next) {
55 | this.notify({
56 | notification: constants.NODE_NOTIFICATIONS.HEALTH_CHECK,
57 | callback: (err, result) => {
58 | if (result.status) {
59 | res.send(result);
60 | } else {
61 | next(WEB_SERVER_CONSTANTS.error_code);
62 | }
63 | }
64 | });
65 | }
66 |
67 | async getStatus(req, res, next) {
68 | this.notify({
69 | notification: constants.NODE_NOTIFICATIONS.GET_WORKER_STATUS,
70 | callback: (err, status) => {
71 | if (err) {
72 | next(WEB_SERVER_CONSTANTS.error_code);
73 | } else {
74 | res.send(status);
75 | }
76 | }
77 | });
78 | }
79 | }
80 |
81 | module.exports = WebServer;
82 |
--------------------------------------------------------------------------------
/src/worker/libp2p-bundle.js:
--------------------------------------------------------------------------------
1 | const libp2p = require("libp2p");
2 | const TCP = require("libp2p-tcp");
3 | const Mplex = require("libp2p-mplex");
4 | const SECIO = require("libp2p-secio");
5 | const KadDHT = require("libp2p-kad-dht");
6 | const defaultsDeep = require("@nodeutils/defaults-deep");
7 | const Bootstrap = require("libp2p-bootstrap");
8 | const SPDY = require("libp2p-spdy");
9 | const WS = require("libp2p-websockets");
10 | // const MulticastDNS = require('libp2p-mdns');
11 |
12 | class PeerBundle extends libp2p {
13 | constructor(_options) {
14 | const defaults = {
15 | modules: {
16 | transport: [TCP, WS],
17 | streamMuxer: [Mplex, SPDY],
18 | connEncryption: [SECIO],
19 | peerDiscovery: [Bootstrap],
20 | dht: KadDHT
21 | },
22 | config: {
23 | dht: {
24 | kBucketSize: 20
25 | },
26 | EXPERIMENTAL: {
27 | dht: true,
28 | pubsub: true
29 | },
30 | peerDiscovery: {
31 | bootstrap: {
32 | interval: 2000,
33 | enabled: false,
34 | list: []
35 | }
36 | }
37 | }
38 | };
39 | const finalConfigurations = defaultsDeep(_options, defaults);
40 | super(finalConfigurations);
41 | }
42 | }
43 |
44 | module.exports = PeerBundle;
45 |
--------------------------------------------------------------------------------
/src/worker/state_sync/receiver/FindProviderResult.js:
--------------------------------------------------------------------------------
1 | class FindProviderResult {
2 | constructor() {
3 | this._map = {};
4 | this._errored = {};
5 | this._completeError = false;
6 | }
7 | setCompleteError() {
8 | this._completeError = true;
9 | }
10 | /**
11 | * add a new mapping
12 | * @param {EngCID} engCid
13 | * @param {Array} providerList
14 | */
15 | addProviderResult(engCid, providerList) {
16 | const key = engCid.getKeccack256();
17 | this._map[key] = { providers: providerList, ecid: engCid };
18 | }
19 | addErroredProviderResult(engCid, error) {
20 | const key = engCid.getKeccack256();
21 | this._errored[key] = { ecid: engCid, error: error };
22 | }
23 | /**
24 | * indicates if there was a general error in the process - the _map will be empty in that case
25 | * @return {boolean}
26 | */
27 | isCompleteError() {
28 | return this._completeError;
29 | }
30 | /**
31 | * indicates if some of the registries has error
32 | * @return {boolean}
33 | */
34 | isErrors() {
35 | if (Object.keys(this._errored).length > 0) {
36 | return true;
37 | } else {
38 | return false;
39 | }
40 | }
41 | getProvidersMap() {
42 | return this._map;
43 | }
44 | getProvidersFor(ecid) {
45 | const key = ecid.getKeccack256();
46 | if (this._map[key]) {
47 | return this._map[key].providers;
48 | }
49 | return null;
50 | }
51 | /** the keys are the keccack hash of each ecid
52 | * @return {Array}*/
53 | getKeysList() {
54 | return Object.keys(this._map);
55 | }
56 | }
57 |
58 | module.exports = FindProviderResult;
59 |
--------------------------------------------------------------------------------
/src/worker/state_sync/receiver/StateSyncReqVerifier.js:
--------------------------------------------------------------------------------
1 | const crypto = require("../../../common/cryptography");
2 | const constants = require("../../../common/constants");
3 | const MSG_TYPES = constants.P2P_MESSAGES;
4 |
5 | class StateSyncReqVerifier {
6 | /**
7 | * Verifies the syncMessage contents with the remoteMissingStates that was requested from Ethereum
8 | * @param {JSON} remoteMissingStates {address : {deltas: {index: deltaHash}, bytecodeHash: hash}}
9 | * @param {SyncMsg} syncMessage
10 | * @param {Function} callback (err, isOk)=>{} - isOk is a flag indicating whether the syncMessage is corresponding to the missing information
11 | * */
12 | static verify(remoteMissingStates, syncMessage, callback) {
13 | let res = true;
14 | let err = null;
15 |
16 | const msgType = syncMessage.type();
17 |
18 | if (msgType === MSG_TYPES.SYNC_STATE_RES) {
19 | const deltas = syncMessage.deltas();
20 | for (let i = 0; i < deltas.length; i++) {
21 | const address = deltas[i].address;
22 | const data = deltas[i].data;
23 | const index = deltas[i].key;
24 | if (!(address in remoteMissingStates)) {
25 | err = "received an unknown address " + address + " in SyncStateRes";
26 | res = false;
27 | break;
28 | }
29 | if (!(index in remoteMissingStates[address].deltas)) {
30 | err = "received an unknown index " + index + " for address " + address;
31 | res = false;
32 | break;
33 | }
34 | if (remoteMissingStates[address].deltas[index] != crypto.hash(data)) {
35 | err = "delta received for address " + address + " in index " + index + " does not match remote hash";
36 | res = false;
37 | break;
38 | }
39 | }
40 | } else {
41 | if (msgType === MSG_TYPES.SYNC_BCODE_RES) {
42 | const address = syncMessage.address();
43 | const bytecodeHash = crypto.hash(syncMessage.bytecode());
44 | if (!(address in remoteMissingStates)) {
45 | err = "received an unknown address " + address + " in SyncBcodeRes";
46 | res = false;
47 | } else if (!("bytecodeHash" in remoteMissingStates[address])) {
48 | err = "received a bytecodeHash for unknown address " + address;
49 | res = false;
50 | } else if (remoteMissingStates[address].bytecodeHash != bytecodeHash) {
51 | err = "bytecodeHash received for address " + address + " does not match remote hash";
52 | res = false;
53 | }
54 | } else {
55 | err = "received an unknown msgType " + msgType;
56 | res = false;
57 | }
58 | }
59 | callback(err, res);
60 | }
61 | }
62 | module.exports = StateSyncReqVerifier;
63 |
--------------------------------------------------------------------------------
/src/worker/tasks/ComputeTask.js:
--------------------------------------------------------------------------------
1 | const Task = require("./Task");
2 | const Result = require("./Result");
3 | const constants = require("../../common/constants");
4 | class ComputeTask extends Task {
5 | /**
6 | * @param {JSON} computeReqMsg , all fields specified in the `expected` list in the func
7 | * @return {ComputeTask} task
8 | * */
9 | static buildTask(computeReqMsg) {
10 | const expected = [
11 | "taskId",
12 | "encryptedArgs",
13 | "encryptedFn",
14 | "userDHKey",
15 | "gasLimit",
16 | "contractAddress",
17 | "blockNumber"
18 | ];
19 | const isMissing = expected.some(attr => {
20 | return !(attr in computeReqMsg);
21 | });
22 | // TODO:: check more stuff in each field when building the task
23 | if (isMissing) {
24 | return null;
25 | } else {
26 | return new ComputeTask(
27 | computeReqMsg.taskId,
28 | computeReqMsg.encryptedArgs,
29 | computeReqMsg.encryptedFn,
30 | computeReqMsg.userDHKey,
31 | computeReqMsg.gasLimit,
32 | computeReqMsg.contractAddress,
33 | computeReqMsg.blockNumber
34 | );
35 | }
36 | }
37 | constructor(taskId, encryptedArgs, encryptedFn, userDHKey, gasLimit, contractAddr, blockNumber) {
38 | super(taskId, constants.CORE_REQUESTS.ComputeTask, contractAddr, gasLimit, blockNumber);
39 | this._encryptedArgs = encryptedArgs;
40 | this._encryptedFn = encryptedFn;
41 | this._userDHKey = userDHKey;
42 | }
43 | getEncryptedArgs() {
44 | return this._encryptedArgs;
45 | }
46 | getEncryptedFn() {
47 | return this._encryptedFn;
48 | }
49 | getUserDHKey() {
50 | return this._userDHKey;
51 | }
52 | toDbJson() {
53 | const output = {
54 | status: this.getStatus(),
55 | taskId: this.getTaskId(),
56 | encryptedArgs: this.getEncryptedArgs(),
57 | encryptedFn: this.getEncryptedFn(),
58 | userDHKey: this.getUserDHKey(),
59 | gasLimit: this.getGasLimit(),
60 | contractAddress: this.getContractAddr(),
61 | blockNumber: this.getBlockNumber()
62 | };
63 | if (this.isFinished()) {
64 | output.result = this._result.toDbJson();
65 | }
66 | return output;
67 | }
68 | toCoreJson() {
69 | return {
70 | encryptedArgs: this.getEncryptedArgs(),
71 | encryptedFn: this.getEncryptedFn(),
72 | userDHKey: this.getUserDHKey(),
73 | gasLimit: this.getGasLimit(),
74 | contractAddress: this.getContractAddr()
75 | };
76 | }
77 | static fromDbJson(taskObj) {
78 | if (taskObj.status) {
79 | const task = ComputeTask.buildTask(taskObj);
80 | task._setStatus(taskObj.status);
81 | if (taskObj.result && taskObj.result.status === constants.TASK_STATUS.SUCCESS) {
82 | const result = Result.ComputeResult.buildComputeResult(taskObj.result);
83 | task.setResult(result);
84 | } else if (taskObj.result) {
85 | const result = Result.FailedResult.buildFailedResult(taskObj.result);
86 | task.setResult(result);
87 | }
88 | return task;
89 | }
90 | return null;
91 | }
92 | }
93 | module.exports = ComputeTask;
94 |
--------------------------------------------------------------------------------
/src/worker/tasks/DeployTask.js:
--------------------------------------------------------------------------------
1 | const Task = require("./Task");
2 | const Result = require("./Result");
3 | const constants = require("../../common/constants");
4 | class DeployTask extends Task {
5 | /**
6 | * @param {JSON} deployReqMsg , all fields specified in the `expected` list in the func
7 | * @return {DeployTask} task
8 | * */
9 | static buildTask(deployReqMsg) {
10 | const expected = [
11 | "taskId",
12 | "preCode",
13 | "encryptedArgs",
14 | "encryptedFn",
15 | "userDHKey",
16 | "gasLimit",
17 | "contractAddress",
18 | "blockNumber"
19 | ];
20 | const isMissing = expected.some(attr => {
21 | return !(attr in deployReqMsg);
22 | });
23 | // TODO:: check more stuff in each field when building the task
24 | if (isMissing) {
25 | return null;
26 | } else {
27 | return new DeployTask(
28 | deployReqMsg.taskId,
29 | deployReqMsg.preCode,
30 | deployReqMsg.encryptedArgs,
31 | deployReqMsg.encryptedFn,
32 | deployReqMsg.userDHKey,
33 | deployReqMsg.gasLimit,
34 | deployReqMsg.contractAddress,
35 | deployReqMsg.blockNumber
36 | );
37 | }
38 | }
39 | constructor(taskId, preCode, encryptedArgs, encryptedFn, userDHKey, gasLimit, contractAddr, blockNumber) {
40 | super(taskId, constants.CORE_REQUESTS.DeploySecretContract, contractAddr, gasLimit, blockNumber);
41 | this._preCode = preCode;
42 | this._encryptedArgs = encryptedArgs;
43 | this._encryptedFn = encryptedFn;
44 | this._userDHKey = userDHKey;
45 | }
46 | getPreCode() {
47 | return this._preCode;
48 | }
49 | getEncryptedArgs() {
50 | return this._encryptedArgs;
51 | }
52 | getEncryptedFn() {
53 | return this._encryptedFn;
54 | }
55 | getUserDHKey() {
56 | return this._userDHKey;
57 | }
58 | toDbJson() {
59 | const output = {
60 | status: this.getStatus(),
61 | taskId: this.getTaskId(),
62 | preCode: this.getPreCode(),
63 | encryptedArgs: this.getEncryptedArgs(),
64 | encryptedFn: this.getEncryptedFn(),
65 | userDHKey: this.getUserDHKey(),
66 | gasLimit: this.getGasLimit(),
67 | contractAddress: this.getContractAddr(),
68 | blockNumber: this.getBlockNumber()
69 | };
70 | if (this.isFinished()) {
71 | output.result = this._result.toDbJson();
72 | }
73 | return output;
74 | }
75 | toCoreJson() {
76 | return {
77 | preCode: this.getPreCode(),
78 | encryptedArgs: this.getEncryptedArgs(),
79 | encryptedFn: this.getEncryptedFn(),
80 | userDHKey: this.getUserDHKey(),
81 | gasLimit: this.getGasLimit(),
82 | contractAddress: this.getContractAddr()
83 | };
84 | }
85 | static fromDbJson(taskObj) {
86 | if (taskObj.status) {
87 | const task = DeployTask.buildTask(taskObj);
88 | task._setStatus(taskObj.status);
89 | if (taskObj.result && taskObj.result.status !== constants.TASK_STATUS.FAILED) {
90 | // here is string
91 | const result = Result.DeployResult.buildDeployResult(taskObj.result);
92 | task.setResult(result);
93 | } else if (taskObj.result) {
94 | const result = Result.FailedResult.buildFailedResult(taskObj.result);
95 | task.setResult(result);
96 | }
97 | return task;
98 | }
99 | return null;
100 | }
101 | }
102 | module.exports = DeployTask;
103 |
--------------------------------------------------------------------------------
/src/worker/tasks/OutsideTask.js:
--------------------------------------------------------------------------------
1 | const Task = require("./Task");
2 | const Result = require("./Result").Result;
3 |
4 | class OutsideTask extends Task {
5 | constructor(taskId, type, result) {
6 | super(taskId, type);
7 | // set task status
8 | this.setResult(result);
9 | }
10 | static buildTask(type, rawResult) {
11 | let result = Result.buildFromRaw(type, rawResult);
12 | if (result) {
13 | return new OutsideTask(result.getTaskId(), type, result);
14 | }
15 | return null;
16 | }
17 | toDbJson() {
18 | let output = {
19 | outsideTask: true,
20 | status: this.getResult().getStatus(),
21 | type: this.getTaskType(),
22 | taskId: this.getTaskId(),
23 | result: this.getResult().toDbJson()
24 | };
25 | return output;
26 | }
27 | static fromDbJson(taskObj) {
28 | if (taskObj.status) {
29 | const task = OutsideTask.buildTask(taskObj.type, taskObj.result);
30 | return task;
31 | }
32 | return null;
33 | }
34 | }
35 |
36 | module.exports = OutsideTask;
37 |
--------------------------------------------------------------------------------
/src/worker/tasks/Task.js:
--------------------------------------------------------------------------------
1 | const constants = require("../../common/constants");
2 | const utils = require("../../common/utils");
3 | const EventEmitter = require("events").EventEmitter;
4 | const Result = require("./Result").Result;
5 |
6 | class Task extends EventEmitter {
7 | constructor(taskId, type, contractAddress, gasLimit, blockNumber) {
8 | super();
9 | this._taskId = utils.remove0x(taskId);
10 | this._status = constants.TASK_STATUS.UNVERIFIED;
11 | this._result = null;
12 | this._type = type;
13 | this._contractAddr = utils.remove0x(contractAddress);
14 | this._gasLimit = gasLimit;
15 | this._blockNumber = blockNumber;
16 | }
17 | /**
18 | * set the task result
19 | * @param {Result} result
20 | * */
21 | setResult(result) {
22 | if (result instanceof Result && result.getTaskId() === this.getTaskId()) {
23 | this._result = result;
24 | if (result.isSuccess()) {
25 | this.setSuccessStatus();
26 | } else {
27 | this.setFailedStatus();
28 | }
29 | }
30 | }
31 | /**
32 | * get the task result
33 | * @return {Result} result or null
34 | * */
35 | getResult() {
36 | return this._result;
37 | }
38 | _setStatus(status) {
39 | this._status = status;
40 | this.emit("status", { taskId: this._taskId, status: status });
41 | }
42 | setInProgressStatus() {
43 | this._setStatus(constants.TASK_STATUS.IN_PROGRESS);
44 | return this;
45 | }
46 | setSuccessStatus() {
47 | this._setStatus(constants.TASK_STATUS.SUCCESS);
48 | return this;
49 | }
50 | setFailedStatus() {
51 | this._setStatus(constants.TASK_STATUS.FAILED);
52 | return this;
53 | }
54 | setGasLimit(gasLimit) {
55 | this._gasLimit = gasLimit;
56 | }
57 | setBlockNumber(blockNumber) {
58 | this._blockNumber = blockNumber;
59 | }
60 | getStatus() {
61 | return this._status;
62 | }
63 | getTaskId() {
64 | return this._taskId;
65 | }
66 | getTaskType() {
67 | return this._type;
68 | }
69 | getGasLimit() {
70 | return this._gasLimit;
71 | }
72 | getContractAddr() {
73 | return this._contractAddr;
74 | }
75 | getBlockNumber() {
76 | return this._blockNumber;
77 | }
78 | isUnverified() {
79 | return this._status === constants.TASK_STATUS.UNVERIFIED;
80 | }
81 | isSuccess() {
82 | return this._status === constants.TASK_STATUS.SUCCESS;
83 | }
84 | isFailed() {
85 | return this._status === constants.TASK_STATUS.FAILED;
86 | }
87 | isFinished() {
88 | return this.isSuccess() || this.isFailed();
89 | }
90 | }
91 | module.exports = Task;
92 |
--------------------------------------------------------------------------------
/test/basic_test.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const testUtils = require("./testUtils/utils");
3 | const assert = require("assert");
4 | const TEST_TREE = require("./test_tree").TEST_TREE;
5 | const WorkerBuilder = require("../src/worker/builder/WorkerBuilder");
6 | const NodeController = require("../src/worker/controller/NodeController");
7 |
8 | const B1Path = path.join(__dirname, "testUtils", "id-l.json");
9 | const B1Port = "10300";
10 |
11 | it("#1 Should test the worker builder", async function() {
12 | let tree = TEST_TREE["basic"];
13 | if (!tree["all"] || !tree["#1"]) {
14 | this.skip();
15 | }
16 |
17 | return new Promise(async resolve => {
18 | // load configs
19 | let c = WorkerBuilder.loadConfig();
20 | // change defaults
21 | c.nickname = "worker";
22 | c.idPath = B1Path;
23 | // build the worker
24 | let worker = WorkerBuilder.build(c);
25 | // start the worker
26 | await worker.syncRun();
27 |
28 | await testUtils.sleep(1000);
29 | assert.strictEqual(0, worker.getAllPeersInfo().length, "peer info don't match ");
30 | // stop the worker
31 | await worker.syncStop();
32 | resolve();
33 | });
34 | });
35 |
36 | it("#2 Should test dialing to a bootstrap", async function() {
37 | let tree = TEST_TREE["basic"];
38 | if (!tree["all"] || !tree["#2"]) {
39 | this.skip();
40 | }
41 | return new Promise(async resolve => {
42 | let bootstrapNodes = ["/ip4/0.0.0.0/tcp/10300/ipfs/QmcrQZ6RJdpYuGvZqD5QEHAv6qX4BrQLJLQPQUrTrzdcgm"];
43 | let bootstrapController = NodeController.initDefaultTemplate({
44 | port: B1Port,
45 | idPath: B1Path,
46 | nickname: "bootstrap",
47 | bootstrapNodes: bootstrapNodes,
48 | extraConfig: {}
49 | });
50 | let peerController = NodeController.initDefaultTemplate({
51 | nickname: "peer",
52 | bootstrapNodes: bootstrapNodes,
53 | extraConfig: {}
54 | });
55 |
56 | await bootstrapController.engNode().syncRun();
57 | await peerController.engNode().syncRun();
58 | await testUtils.sleep(3000);
59 |
60 | assert.strictEqual(bootstrapController.isConnected(peerController.getSelfB58Id()), true);
61 | assert.strictEqual(bootstrapController.getConnectedPeers().length, 1);
62 | assert.strictEqual(peerController.isConnected(bootstrapController.getSelfB58Id()), true);
63 | assert.strictEqual(peerController.getConnectedPeers().length, 1);
64 |
65 | await bootstrapController.engNode().syncStop();
66 | await peerController.engNode().syncStop();
67 | resolve();
68 | });
69 | });
70 |
71 | it("#3 Should test libp2p discovery", async function() {
72 | let tree = TEST_TREE["basic"];
73 | if (!tree["all"] || !tree["#3"]) {
74 | this.skip();
75 | }
76 |
77 | return new Promise(async (resolve, reject) => {
78 | let nodesNum = 10;
79 | let bootstrapNodes = ["/ip4/0.0.0.0/tcp/10300/ipfs/QmcrQZ6RJdpYuGvZqD5QEHAv6qX4BrQLJLQPQUrTrzdcgm"];
80 | let bNode = NodeController.initDefaultTemplate({
81 | port: B1Port,
82 | idPath: B1Path,
83 | nickname: "bootstrap",
84 | bootstrapNodes: bootstrapNodes,
85 | extraConfig: {}
86 | });
87 |
88 | let peers = [];
89 |
90 | for (let i = 0; i < nodesNum; i++) {
91 | let p = NodeController.initDefaultTemplate({
92 | nickname: "peer" + i,
93 | bootstrapNodes: bootstrapNodes,
94 | extraConfig: {}
95 | });
96 | peers.push(p);
97 | }
98 |
99 | // init bootstrap nodes
100 | await bNode.engNode().syncRun();
101 |
102 | // init peer nodes
103 | for (let i = 0; i < nodesNum; i++) {
104 | await peers[i].engNode().syncRun();
105 | }
106 |
107 | await testUtils.sleep(3000);
108 |
109 | assert.strictEqual(bNode.getConnectedPeers().length, nodesNum);
110 | for (let i = 0; i < nodesNum; ++i) {
111 | assert.strictEqual(bNode.getConnectedPeers().length, nodesNum);
112 | }
113 |
114 | for (let i = 0; i < nodesNum; ++i) {
115 | await peers[i].engNode().syncStop();
116 | }
117 | await bNode.engNode().syncStop();
118 | resolve();
119 | });
120 | });
121 |
--------------------------------------------------------------------------------
/test/ethereum/EnigmaContractMock.js:
--------------------------------------------------------------------------------
1 | class EnigmaContractMock {
2 | constructor() {
3 | this._taskRecords = {};
4 | this._contracts = {};
5 | this._epochSize = null;
6 | this._taskTimeout = 0;
7 | this._ethereumBlockNumber = 0;
8 | this._eventListeners = {};
9 | this._workersParams = [];
10 | this._except = false;
11 | }
12 |
13 | setTaskParams(taskId, blockNumber, status, gasLimit, inputsHash, outputHash) {
14 | this._taskRecords[taskId] = {
15 | taskId: taskId,
16 | blockNumber: blockNumber,
17 | status: status,
18 | gasLimit: gasLimit,
19 | inputsHash: inputsHash,
20 | outputHash: outputHash
21 | };
22 | }
23 |
24 | setContractParams(contractAddress, codeHash, deltas) {
25 | this._contracts[contractAddress] = {
26 | codeHash: codeHash,
27 | deltaHashes: deltas
28 | };
29 | }
30 |
31 | setEpochSize(size) {
32 | this._epochSize = size;
33 | }
34 |
35 | setWorkerParams(workerParams) {
36 | this._workersParams = workerParams;
37 | }
38 |
39 | setTaskTimeout(blocks) {
40 | this._taskTimeout = blocks;
41 | }
42 |
43 | setEthereumBlockNumber(number) {
44 | this._ethereumBlockNumber = number;
45 | }
46 |
47 | getTaskParams(taskId) {
48 | if (this._except) {
49 | throw Error("Ethereum Mock exception");
50 | }
51 | return this._taskRecords[taskId];
52 | }
53 |
54 | getEpochSize() {
55 | return this._epochSize;
56 | }
57 |
58 | getWorkersParams() {
59 | return this._workersParams;
60 | }
61 |
62 | getContractParams(contractAddress) {
63 | return this._contracts[contractAddress];
64 | }
65 |
66 | getTaskTimeout() {
67 | return this._taskTimeout;
68 | }
69 |
70 | getEthereumBlockNumber() {
71 | return this._ethereumBlockNumber;
72 | }
73 |
74 | getEthereumBlockNumberAsync(cb) {
75 | cb(null, this._ethereumBlockNumber);
76 | }
77 |
78 | subscribe(eventName, filter, callback) {
79 | this._eventListeners[eventName] = callback;
80 | }
81 |
82 | triggerEvent(eventName, event) {
83 | this._eventListeners[eventName](null, event);
84 | }
85 |
86 | triggerException() {
87 | this._except = true;
88 | }
89 |
90 | w3() {
91 | return {
92 | eth: { getBlockNumber: this.getEthereumBlockNumberAsync.bind(this) }
93 | };
94 | }
95 | }
96 |
97 | module.exports = EnigmaContractMock;
98 |
--------------------------------------------------------------------------------
/test/ethereum/EthereumAPIMock.js:
--------------------------------------------------------------------------------
1 | const EnigmaContractMock = require("./EnigmaContractMock");
2 | const EthereumAPI = require("../../src/ethereum/EthereumAPI");
3 | const EthereumServices = require("../../src/ethereum/EthereumServices");
4 | const EthereumVerifier = require("../../src/ethereum/EthereumVerifier");
5 |
6 | class EthereumAPIMock extends EthereumAPI {
7 | constructor(logger) {
8 | super(logger);
9 | this._api = new EnigmaContractMock();
10 | this._services = new EthereumServices(this._api);
11 | this._verifier = new EthereumVerifier(this._api, this._services, logger);
12 | }
13 |
14 | async init() {
15 | this._services.initServices();
16 | await this._verifier.init();
17 | }
18 |
19 | async destroy() {}
20 | }
21 |
22 | module.exports = EthereumAPIMock;
23 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/contracts/EnigmaToken.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.12;
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 | }
69 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/contracts/ExchangeRate.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.12;
2 | pragma experimental ABIEncoderV2;
3 |
4 | contract ExchangeRate {
5 |
6 | constructor() public {
7 |
8 | }
9 |
10 | function getExchangeRate() public view returns (uint256) {
11 | return 164518;// 0.00164518
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/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 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/contracts/impl/EnigmaEvents.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.12;
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 Unregistered(address custodian);
13 | event WorkersParameterized(uint seed, uint256 firstBlockNumber, uint256 inclusionBlockNumber, address[] workers,
14 | uint[] stakes, uint nonce);
15 | event TaskRecordCreated(bytes32 indexed taskId, bytes32 inputsHash, uint64 gasLimit, uint64 gasPx, address sender,
16 | uint blockNumber);
17 | // ReceiptVerified => bytes32s [scAddr, taskId, stateDeltaHash, outputHash]
18 | event ReceiptVerified(bytes32 indexed taskId, uint64 gasUsed, address optionalEthereumContractAddress,
19 | bytes32[4] bytes32s, uint deltaHashIndex, uint gasUsedTotal, bytes optionalEthereumData, address workerAddress);
20 | event ReceiptFailed(bytes32 indexed taskId, bytes32 scAddr, bytes32 outputHash,
21 | uint gasUsed, address workerAddress);
22 | event ReceiptFailedETH(bytes32 indexed taskId, bytes32 scAddr, uint gasUsed, uint gasUsedTotal,
23 | address workerAddress);
24 | event TaskFeeReturned(bytes32 indexed taskId);
25 | event DepositSuccessful(address from, uint value);
26 | event WithdrawSuccessful(address to, uint value);
27 | // SecretContractDeployed => bytes32s [taskId, preCodeHash, codeHash, initStateDeltaHash]
28 | event SecretContractDeployed(bytes32 indexed taskId, uint64 gasUsed, address optionalEthereumContractAddress,
29 | bytes32[4] bytes32s, uint gasUsedTotal, bytes optionalEthereumData, address workerAddress);
30 | event LoggedIn(address workerAddress);
31 | event LoggedOut(address workerAddress);
32 | }
33 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/contracts/impl/EnigmaState.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.12;
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 | address exchangeRate;
33 | address updatedEnigmaContractAddress;
34 |
35 | address oldEnigmaContractAddress;
36 |
37 | /**
38 | * The last 5 worker parameters
39 | * We keep a collection of worker parameters to account for latency issues.
40 | * A computation task might be conceivably given out at a certain block number
41 | * but executed at a later block in a different epoch. It follows that
42 | * the contract must have access to the worker parameters effective when giving
43 | * out the task, otherwise the selected worker would not match. We calculated
44 | * that keeping the last 5 items should be more than enough to account for
45 | * all latent tasks. Tasks results will be rejected past this limit.
46 | */
47 | EnigmaCommon.WorkersParams[5] workersParams;
48 |
49 | // An address-based index of all registered worker
50 | address[] workerAddresses;
51 | // An address-based index of all secret contracts
52 | bytes32[] scAddresses;
53 |
54 | // A registry of all registered workers with their attributes
55 | mapping(address => EnigmaCommon.Worker) workers;
56 |
57 | mapping(address => address) stakingToOperatingAddresses;
58 |
59 | // A registry of all tasks with their attributes
60 | mapping(bytes32 => EnigmaCommon.TaskRecord) tasks;
61 |
62 | // An array of all task IDs
63 | bytes32[] taskIds;
64 |
65 | // A registry of all deployed secret contracts with their attributes
66 | mapping(bytes32 => EnigmaCommon.SecretContract) contracts;
67 |
68 | // A mapping of number of tasks deployed for each address
69 | mapping(address => uint) userTaskDeployments;
70 |
71 | // TODO: do we keep tasks forever? if not, when do we delete them?
72 | uint stakingThreshold;
73 | uint workerGroupSize;
74 |
75 | bool debug;
76 | bytes mrSigner;
77 | bytes isvSvn;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/contracts/impl/EnigmaStorage.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.12;
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 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/contracts/impl/SecretContractImpl.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.12;
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 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/contracts/impl/UpgradeImpl.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.12;
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 { Bytes } from "../utils/Bytes.sol";
10 |
11 | /**
12 | * @author Enigma
13 | *
14 | * Library that maintains functionality associated with tasks
15 | */
16 | library UpgradeImpl {
17 | using SafeMath for uint256;
18 | using SafeMath for uint64;
19 | using ECDSA for bytes32;
20 | using Bytes for address;
21 |
22 | function upgradeEnigmaContractImpl(
23 | EnigmaState.State storage state,
24 | address _updatedEnigmaContractAddress
25 | )
26 | public
27 | {
28 | state.updatedEnigmaContractAddress = _updatedEnigmaContractAddress;
29 |
30 | for (uint i = 0; i < state.taskIds.length; i++) {
31 | if (state.tasks[state.taskIds[i]].status == EnigmaCommon.TaskStatus.RecordCreated) {
32 | EnigmaCommon.TaskRecord storage task = state.tasks[state.taskIds[i]];
33 |
34 | // Return the full fee to the task sender
35 | require(state.engToken.transfer(task.sender, task.gasLimit.mul(task.gasPx)), "Token transfer failed");
36 |
37 | // Set task's status to ReceiptFailed and emit event
38 | task.status = EnigmaCommon.TaskStatus.ReceiptFailedReturn;
39 | }
40 | }
41 | }
42 |
43 | function transferWorkerStakePostUpgradeImpl(
44 | EnigmaState.State storage state,
45 | address _operatingAddress,
46 | address _stakingAddress,
47 | bytes memory _sig
48 | )
49 | public
50 | returns (uint256)
51 | {
52 | require(state.workers[_operatingAddress].stakingAddress == _stakingAddress,
53 | "Invalid staking address for registration balance transfer");
54 | // Verify the worker's signature
55 | bytes memory message;
56 | message = EnigmaCommon.appendMessage(message, state.updatedEnigmaContractAddress.toBytes());
57 | bytes32 msgHash = keccak256(message);
58 | require(msgHash.toEthSignedMessageHash().recover(_sig) == _operatingAddress, "Invalid signature");
59 | EnigmaCommon.Worker storage worker = state.workers[_operatingAddress];
60 | uint256 oldWorkerBalance = worker.balance;
61 | worker.balance = 0;
62 | require(state.engToken.transfer(state.updatedEnigmaContractAddress, oldWorkerBalance),
63 | "Token transfer failed");
64 | return oldWorkerBalance;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/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 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/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 getSigningAddress() external view returns (address);
11 | }
12 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/contracts/interfaces/IExchangeRate.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.0;
2 | pragma experimental ABIEncoderV2;
3 |
4 | interface IExchangeRate {
5 | function getExchangeRate() external view returns (uint256);
6 | }
7 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/contracts/utils/GetCode2.sol:
--------------------------------------------------------------------------------
1 | pragma solidity ^0.5.0;
2 |
3 | library GetCode2 {
4 | function at(address _addr) internal view returns (bytes memory o_code) {
5 | assembly {
6 | // retrieve the size of the code, this needs assembly
7 | let size := extcodesize(_addr)
8 | // allocate output byte array - this could also be done without assembly
9 | // by using o_code = new bytes(size)
10 | o_code := mload(0x40)
11 | // new "memory end" including padding
12 | mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
13 | // store length in memory
14 | mstore(o_code, size)
15 | // actually retrieve the code, this needs assembly
16 | extcodecopy(_addr, add(o_code, 0x20), 0, size)
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/env_initializer.js:
--------------------------------------------------------------------------------
1 | const { exec, spawn } = require("child_process");
2 | const Web3 = require("web3");
3 |
4 | const testUtils = require("../../testUtils/utils");
5 | const path = require("path");
6 |
7 | let subprocess; // Global `trufffle develop` "child process" object
8 |
9 | function buildEnv(truffleDirectory) {
10 | return new Promise((resolve, reject) => {
11 | const command = "cd " + truffleDirectory + " && npx truffle compile && cd " + process.cwd();
12 | exec(command, (err, stdout, stderr) => {
13 | if (err) {
14 | reject("env_initializer.buildEnv " + err);
15 | }
16 | //console.log(stdout);
17 | resolve(stderr, stdout);
18 | });
19 | });
20 | }
21 |
22 | function resetEnv(truffleDirectory) {
23 | return new Promise((resolve, reject) => {
24 | const command = "cd " + truffleDirectory + " && npx truffle migrate --reset && cd " + process.cwd();
25 | exec(command, (err, stdout, stderr) => {
26 | if (err) {
27 | reject("env_initalizer.resetEnv " + err);
28 | }
29 | //console.log(stdout);
30 | resolve(stderr, stdout);
31 | });
32 | });
33 | }
34 |
35 | async function init(truffleDirectory) {
36 | await buildEnv(truffleDirectory);
37 | await resetEnv(truffleDirectory);
38 |
39 | //await testUtils.sleep(3000);
40 |
41 | const truffleConfig = require(path.join(truffleDirectory, "truffle"));
42 | const EnigmaContractJson = require("./build/contracts/Enigma.json"); //require('./build/contracts/EnigmaMock.json');
43 | //const EnigmaTokenContractJson = require('./build/contracts/EnigmaToken.json');
44 |
45 | const websocketProvider = "ws://127.0.0.1:9545";
46 | const provider = new Web3.providers.WebsocketProvider(websocketProvider);
47 |
48 | // from https://github.com/ethereum/web3.js/issues/1354
49 | // provider.on('error', (e) => console.error('WS Error: ', e)); // provider.on('error', e => console.error('WS Error', e));
50 | // provider.on('end', (e) => console.log('WS End')); // provider.on('end', e => console.error('WS End', e));
51 |
52 | const web3 = new Web3(provider);
53 |
54 | // const accounts = await web3.eth.getAccounts();
55 | //
56 | // const sender1 = accounts[0];
57 | // const sender2 = accounts[1];
58 | // const principal = accounts[2];// '0x627306090abab3a6e1400e9345bc60c78a8bef57';
59 | //
60 | // const enigmaTokenContract = new web3.eth.Contract(EnigmaTokenContractJson.abi);
61 | //
62 | // const enigmaTokenContractInstance = await enigmaTokenContract.deploy({data: EnigmaTokenContractJson.bytecode, arguments: []})
63 | // .send({
64 | // from: sender1,
65 | // gas: 1500000,
66 | // // gasPrice: '100000000000'
67 | // });
68 | //
69 | // // console.log('using account', principal, 'as principal signer');
70 | //
71 | // const enigmaContract = new web3.eth.Contract(EnigmaContractJson.abi);
72 | // const enigmaContractInstance = await enigmaContract.deploy({
73 | // data: EnigmaContractJson.bytecode,
74 | // arguments: [enigmaTokenContractInstance.options.address, principal],
75 | // }).send({
76 | // from: sender2,
77 | // gas: 6500000, // 4500000,
78 | // // gasPrice: '100000000000'
79 | // });
80 | //
81 | // await testUtils.sleep(1000);
82 |
83 | const networkId = truffleConfig.networks.development.network_id;
84 |
85 | return {
86 | contractAddress: EnigmaContractJson.networks[networkId].address,
87 | contractABI: EnigmaContractJson.abi,
88 | web3: web3
89 | };
90 | }
91 |
92 | async function startNetwork(truffleDirectory) {
93 | const command = "cd " + truffleDirectory + " && npx truffle develop";
94 | subprocess = spawn(command, {
95 | shell: true,
96 | detached: true
97 | });
98 |
99 | subprocess.unref();
100 |
101 | await testUtils.sleep(3000);
102 | }
103 |
104 | async function start(truffleDirectory) {
105 | await startNetwork(truffleDirectory);
106 | }
107 |
108 | function stop() {
109 | subprocess.kill();
110 | }
111 |
112 | function disconnect(web3) {
113 | web3.currentProvider.disconnect();
114 | }
115 |
116 | module.exports = {
117 | start: start,
118 | stop: stop,
119 | init: init,
120 | disconnect: disconnect
121 | };
122 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/migrations/1_initial_migration.js:
--------------------------------------------------------------------------------
1 | var Migrations = artifacts.require("./Migrations.sol");
2 |
3 | module.exports = function(deployer) {
4 | deployer.deploy(Migrations);
5 | };
6 |
7 | // const EnigmaToken = artifacts.require('EnigmaToken.sol');
8 | // const Enigma = artifacts.require('Enigma.sol');
9 |
10 | // module.exports = function(deployer) {
11 | // return deployer.then(() => {
12 | // return deployer.deploy(EnigmaToken);
13 | // }).then(() => {
14 | // const principal = '0x627306090abab3a6e1400e9345bc60c78a8bef57';
15 | // console.log('using account', principal, 'as principal signer');
16 | // return deployer.deploy(Enigma, EnigmaToken.address, principal);
17 | // });
18 | // };
19 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/migrations/2_deploy_contracts.js:
--------------------------------------------------------------------------------
1 | const EnigmaToken = artifacts.require("EnigmaToken.sol");
2 | const SolRsaVerify = artifacts.require("./utils/SolRsaVerify.sol");
3 | const SecretContractImpl = artifacts.require("./impl/SecretContractImpl.sol");
4 | const ExchangeRate = artifacts.require("ExchangeRate.sol");
5 | const UpgradeImpl = artifacts.require("./impl/UpgradeImpl.sol");
6 |
7 | const PRINCIPAL_SIGNING_ADDRESS = "0x3078356633353161633136306365333763653066";
8 | const ISVSVN = "0x0000";
9 | const MRSIGNER = "0x83d719e77deaca1470f6baf62a4d774303c899db69020f9c70ee1dfc08c7ce9e";
10 | const EPOCH_SIZE = 10;
11 | const TIMEOUT_THRESHOLD = 2;
12 | const DEBUG = false;
13 |
14 | const Enigma = artifacts.require("Enigma.sol");
15 | const WorkersImpl = artifacts.require("./impl/WorkersImpl.sol");
16 | const PrincipalImpl = artifacts.require("./impl/PrincipalImpl.sol");
17 | const TaskImpl = artifacts.require("./impl/TaskImpl.sol");
18 |
19 | async function deployProtocol(deployer) {
20 | await Promise.all([
21 | deployer.deploy(EnigmaToken),
22 | deployer.deploy(SolRsaVerify),
23 | deployer.deploy(WorkersImpl),
24 | deployer.deploy(SecretContractImpl),
25 | deployer.deploy(UpgradeImpl)
26 | ]);
27 |
28 | await Promise.all([
29 | TaskImpl.link("WorkersImpl", WorkersImpl.address),
30 | PrincipalImpl.link("WorkersImpl", WorkersImpl.address)
31 | ]);
32 |
33 | await Promise.all([deployer.deploy(TaskImpl), deployer.deploy(PrincipalImpl)]);
34 |
35 | await Promise.all([
36 | Enigma.link("WorkersImpl", WorkersImpl.address),
37 | Enigma.link("PrincipalImpl", PrincipalImpl.address),
38 | Enigma.link("TaskImpl", TaskImpl.address),
39 | Enigma.link("UpgradeImpl", UpgradeImpl.address),
40 | Enigma.link("SecretContractImpl", SecretContractImpl.address)
41 | ]);
42 |
43 | let principal = PRINCIPAL_SIGNING_ADDRESS;
44 | console.log("using account", principal, "as principal signer");
45 | await deployer.deploy(ExchangeRate);
46 | await deployer.deploy(
47 | Enigma,
48 | EnigmaToken.address,
49 | principal,
50 | ExchangeRate.address,
51 | EPOCH_SIZE,
52 | TIMEOUT_THRESHOLD,
53 | DEBUG,
54 | MRSIGNER,
55 | ISVSVN
56 | );
57 | }
58 |
59 | async function doMigration(deployer) {
60 | await deployProtocol(deployer);
61 | }
62 |
63 | module.exports = function(deployer) {
64 | deployer.then(() => doMigration(deployer));
65 | };
66 |
--------------------------------------------------------------------------------
/test/ethereum/scripts/truffle.js:
--------------------------------------------------------------------------------
1 | // See
2 | // to customize your Truffle configuration!
3 | module.exports = {
4 | networks: {
5 | development: {
6 | host: "localhost",
7 | port: 9545,
8 | network_id: "5777" // Match any network id
9 | }
10 | },
11 | solc: {
12 | // Turns on the Solidity optimizer. For development the optimizer's
13 | // quite helpful, just remember to be careful, and potentially turn it
14 | // off, for live deployment and/or audit time. For more information,
15 | // see the Truffle 4.0.0 release notes.
16 | //
17 | // https://github.com/trufflesuite/truffle/releases/tag/v4.0.0
18 | optimizer: {
19 | enabled: true,
20 | runs: 200
21 | }
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/test/msg_test.js:
--------------------------------------------------------------------------------
1 | const assert = require("assert");
2 | const syncMsgs = require("../src/policy/p2p_messages/sync_messages");
3 | const schemeValidator = require("../src/policy/p2p_messages/schemes/SchemeValidator");
4 | const constants = require("../src/common/constants");
5 | const MsgTypes = constants.P2P_MESSAGES;
6 |
7 | it("should scheme validate state sync req", function(done) {
8 | let state_sync_req_obj = {
9 | msgType: "SYNC_STATE_REQ",
10 | contractAddress: "0x...",
11 | fromIndex: 1,
12 | toIndex: 101,
13 | fromHash: "0x...",
14 | toHash: "0x..."
15 | };
16 |
17 | schemeValidator.validateScheme(state_sync_req_obj, MsgTypes.SYNC_STATE_REQ, (err, isValid) => {
18 | if (err) {
19 | assert.strictEqual(false, true, err);
20 | } else {
21 | assert.strictEqual(true, isValid, "invalid scheme");
22 | }
23 | done();
24 | });
25 | });
26 |
27 | it("should scheme validate state sync res", function(done) {
28 | let state_sync_res_obj = {
29 | msgType: "SYNC_STATE_RES",
30 | contractAddress: "0x...",
31 | states: [
32 | { index: 1, hash: "0x1", data: [11, 12, 13] },
33 | { index: 2, hash: "0x2", data: [311, 122, 133] },
34 | { index: 3, hash: "0x3", data: [151, 152, 143] }
35 | ]
36 | };
37 |
38 | schemeValidator.validateScheme(state_sync_res_obj, MsgTypes.SYNC_STATE_RES, (err, isValid) => {
39 | if (err) {
40 | assert.strictEqual(false, true, err);
41 | } else {
42 | assert.strictEqual(true, isValid, "invalid scheme");
43 | }
44 | done();
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/test/singleConfig/config_1.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | logger: {
3 | level: "debug", // log level
4 | cli: true, // output to std
5 | file: false // output to file, if set path then will save to file else none.
6 | },
7 | node: {
8 | network: {
9 | port: "0", // if 0 then chose random port,
10 | multiAddrs: ["/ip4/0.0.0.0/tcp/"],
11 | // TODO:: ignored because of constants/namespace
12 | namespace: "ipfs",
13 | bootstrapNodes: ["/ip4/0.0.0.0/tcp/10300/ipfs/QmcrQZ6RJdpYuGvZqD5QEHAv6qX4BrQLJLQPQUrTrzdcgm"]
14 | },
15 | idPath: null, // load PeerId, if null-> create one
16 | // TODO:: ignored currently cuz of implementation
17 | id: null, // either idPath or id -> actuall object here are acceptable if both are set, idPath is the default
18 | // TODO:: ignored libp2p-bundle
19 | isDiscover: true, // should do discovery ?
20 | // the inner task manager of the node controller
21 | taskManager: {
22 | dbPath: null // the db path for storage, if null saves in default
23 | },
24 | // epoch related config
25 | principalNode: {
26 | uri: null //principal node url, default if null
27 | }
28 | },
29 | // IPC
30 | core: {
31 | uri: "tcp://127.0.0.1:5522" // ipc uri
32 | },
33 | // JsonRpc config
34 | proxy: {
35 | withProxy: true, // default serve as a proxy node
36 | port: null // integer or null will default in constants
37 | },
38 | // Ethereum related configuration
39 | ethereum: {
40 | //default use ethereum or not
41 | withEthereum: false,
42 | // websocket provider
43 | ethereumWebsocketProvider: "",
44 | // enigma contract address
45 | enigmaContractAddress: ""
46 | },
47 | // TODO:: CURRENTLY IGNORED
48 | "dev:": {
49 | truffleDir: ""
50 | }
51 | };
52 |
--------------------------------------------------------------------------------
/test/singleConfig/config_2_bootstrap.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | logger: {
3 | level: "debug", // log level
4 | cli: true, // output to std
5 | file: false // output to file, if set path then will save to file else none.
6 | },
7 | node: {
8 | network: {
9 | port: "10300", // if 0 then chose random port,
10 | multiAddrs: ["/ip4/0.0.0.0/tcp/"],
11 | // TODO:: ignored because of constants/namespace
12 | namespace: "ipfs",
13 | bootstrapNodes: ["/ip4/0.0.0.0/tcp/10300/ipfs/QmcrQZ6RJdpYuGvZqD5QEHAv6qX4BrQLJLQPQUrTrzdcgm"]
14 | },
15 | idPath: "./id-j.json", // load PeerId, if null-> create one
16 | // TODO:: ignored currently cuz of implementation
17 | id: null, // either idPath or id -> actuall object here are acceptable if both are set, idPath is the default
18 | // TODO:: ignored libp2p-bundle
19 | isDiscover: true, // should do discovery ?
20 | // the inner task manager of the node controller
21 | taskManager: {
22 | dbPath: null // the db path for storage, if null saves in default
23 | },
24 | // epoch related config
25 | principalNode: {
26 | uri: null //principal node url, default if null
27 | }
28 | },
29 | // IPC
30 | core: {
31 | uri: "tcp://127.0.0.1:5533" // ipc uri
32 | },
33 | // JsonRpc config
34 | proxy: {
35 | withProxy: true, // default serve as a proxy node
36 | port: 3001 // integer or null will default in constants
37 | },
38 | // Ethereum related configuration
39 | ethereum: {
40 | //default use ethereum or not
41 | withEthereum: false,
42 | // websocket provider
43 | ethereumWebsocketProvider: "",
44 | // enigma contract address
45 | enigmaContractAddress: ""
46 | },
47 | // TODO:: CURRENTLY IGNORED
48 | "dev:": {
49 | truffleDir: ""
50 | }
51 | };
52 |
--------------------------------------------------------------------------------
/test/singleConfig/id-l.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "QmcrQZ6RJdpYuGvZqD5QEHAv6qX4BrQLJLQPQUrTrzdcgm",
3 | "privKey": "CAASqAkwggSkAgEAAoIBAQDLZZcGcbe4urMBVlcHgN0fpBymY+xcr14ewvamG70QZODJ1h9sljlExZ7byLiqRB3SjGbfpZ1FweznwNxWtWpjHkQjTVXeoM4EEgDSNO/Cg7KNlU0EJvgPJXeEPycAZX9qASbVJ6EECQ40VR/7+SuSqsdL1hrmG1phpIju+D64gLyWpw9WEALfzMpH5I/KvdYDW3N4g6zOD2mZNp5y1gHeXINHWzMF596O72/6cxwyiXV1eJ000k1NVnUyrPjXtqWdVLRk5IU1LFpoQoXZU5X1hKj1a2qt/lZfH5eOrF/ramHcwhrYYw1txf8JHXWO/bbNnyemTHAvutZpTNrsWATfAgMBAAECggEAQj0obPnVyjxLFZFnsFLgMHDCv9Fk5V5bOYtmxfvcm50us6ye+T8HEYWGUa9RrGmYiLweuJD34gLgwyzE1RwptHPj3tdNsr4NubefOtXwixlWqdNIjKSgPlaGULQ8YF2tm/kaC2rnfifwz0w1qVqhPReO5fypL+0ShyANVD3WN0Fo2ugzrniCXHUpR2sHXSg6K+2+qWdveyjNWog34b7CgpV73Ln96BWae6ElU8PR5AWdMnRaA9ucA+/HWWJIWB3Fb4+6uwlxhu2L50Ckq1gwYZCtGw63q5L4CglmXMfIKnQAuEzazq9T4YxEkp+XDnVZAOgnQGUBYpetlgMmkkh9qQKBgQDvsEs0ThzFLgnhtC2Jy//ZOrOvIAKAZZf/mS08AqWH3L0/Rjm8ZYbLsRcoWU78sl8UFFwAQhMRDBP9G+RPojWVahBL/B7emdKKnFR1NfwKjFdDVaoX5uNvZEKSl9UubbC4WZJ65u/cd5jEnj+w3ir9G8n+P1gp/0yBz02nZXFgSwKBgQDZPQr4HBxZL7Kx7D49ormIlB7CCn2i7mT11Cppn5ifUTrp7DbFJ2t9e8UNk6tgvbENgCKXvXWsmflSo9gmMxeEOD40AgAkO8Pn2R4OYhrwd89dECiKM34HrVNBzGoB5+YsAno6zGvOzLKbNwMG++2iuNXqXTk4uV9GcI8OnU5ZPQKBgCZUGrKSiyc85XeiSGXwqUkjifhHNh8yH8xPwlwGUFIZimnD4RevZI7OEtXw8iCWpX2gg9XGuyXOuKORAkF5vvfVriV4e7c9Ad4Igbj8mQFWz92EpV6NHXGCpuKqRPzXrZrNOA9PPqwSs+s9IxI1dMpk1zhBCOguWx2m+NP79NVhAoGBAI6WSoTfrpu7ewbdkVzTWgQTdLzYNe6jmxDf2ZbKclrf7lNr/+cYIK2Ud5qZunsdBwFdgVcnu/02czeS42TvVBgs8mcgiQc/Uy7yi4/VROlhOnJTEMjlU2umkGc3zLzDgYiRd7jwRDLQmMrYKNyEr02HFKFn3w8kXSzW5I8rISnhAoGBANhchHVtJd3VMYvxNcQb909FiwTnT9kl9pkjhwivx+f8/K8pDfYCjYSBYCfPTM5Pskv5dXzOdnNuCj6Y2H/9m2SsObukBwF0z5Qijgu1DsxvADVIKZ4rzrGb4uSEmM6200qjJ/9U98fVM7rvOraakrhcf9gRwuspguJQnSO9cLj6",
4 | "pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLZZcGcbe4urMBVlcHgN0fpBymY+xcr14ewvamG70QZODJ1h9sljlExZ7byLiqRB3SjGbfpZ1FweznwNxWtWpjHkQjTVXeoM4EEgDSNO/Cg7KNlU0EJvgPJXeEPycAZX9qASbVJ6EECQ40VR/7+SuSqsdL1hrmG1phpIju+D64gLyWpw9WEALfzMpH5I/KvdYDW3N4g6zOD2mZNp5y1gHeXINHWzMF596O72/6cxwyiXV1eJ000k1NVnUyrPjXtqWdVLRk5IU1LFpoQoXZU5X1hKj1a2qt/lZfH5eOrF/ramHcwhrYYw1txf8JHXWO/bbNnyemTHAvutZpTNrsWATfAgMBAAE="
5 | }
6 |
--------------------------------------------------------------------------------
/test/singleConfig/single_config_test.js:
--------------------------------------------------------------------------------
1 | const EnvironmentBuilder = require("../../src/main_controller/EnvironmentBuilder");
2 | const CoreServer = require("../../src/core/core_server_mock/core_server");
3 | const tree = require("../test_tree").TEST_TREE.single_config;
4 | const expect = require("expect");
5 | const assert = require("assert");
6 | const MainController = require("../../src/main_controller/FacadeController");
7 | const testUtils = require("../testUtils/utils");
8 | const path = require("path");
9 | const ID_B_PATH = path.join(__dirname, "id-l.json");
10 | const jayson = require("jayson");
11 |
12 | function getRpcClient(port) {
13 | return jayson.client.http("http://localhost:" + port);
14 | }
15 | function getConfig() {
16 | return require("./config_1");
17 | }
18 | function getBootsrapConfig() {
19 | let c = require("./config_2_bootstrap");
20 | c.node.idPath = ID_B_PATH;
21 | return c;
22 | }
23 |
24 | function getCoreServer(uri) {
25 | coreServer = new CoreServer();
26 | coreServer.runServer(uri);
27 | return coreServer;
28 | }
29 |
30 | describe("single_config_tests", () => {
31 | it("#1 Should create node and shutdown", async function() {
32 | if (!tree["all"] || !tree["#1"]) {
33 | this.skip();
34 | }
35 | const c = getConfig();
36 | return new Promise(async resolve => {
37 | let coreServer = getCoreServer(c.core.uri);
38 | let mainController = await EnvironmentBuilder.buildFromSingle(c);
39 | expect(mainController).toEqual(expect.anything());
40 | assert(mainController instanceof MainController, "not main controller");
41 | await mainController.shutdownSystem();
42 | coreServer.disconnect();
43 | resolve();
44 | });
45 | });
46 | it("#2 Should test with proxy and shutdown", async function() {
47 | if (!tree["all"] || !tree["#2"]) {
48 | this.skip();
49 | }
50 | return new Promise(async (resolve, reject) => {
51 | await testUtils.sleep(2000);
52 | const c = getConfig();
53 | const bc = getBootsrapConfig();
54 | let bCoreServer = getCoreServer(bc.core.uri);
55 | let pCoreServer = getCoreServer(c.core.uri);
56 | let bMainController = await EnvironmentBuilder.buildFromSingle(bc);
57 | let pMainController = await EnvironmentBuilder.buildFromSingle(c);
58 | let client = getRpcClient(bc.proxy.port);
59 | // verify connectivity
60 | expect(pMainController).toEqual(expect.anything());
61 | assert(pMainController instanceof MainController, "not main controller");
62 | assert(bMainController instanceof MainController, "not main controller");
63 | await testUtils.sleep(5000);
64 | // rpc
65 | let signKey = await pMainController.getNode().selfSubscribeAction();
66 | await testUtils.sleep(1000);
67 | const userPubKey =
68 | "5587fbc96b01bfe6482bf9361a08e84810afcc0b1af72a8e4520f9" +
69 | "8771ea1080681e8a2f9546e5924e18c047fa948591dba098bffaced50f97a41b0050bdab99";
70 | client.request("getWorkerEncryptionKey", { workerAddress: signKey, userPubKey: userPubKey }, async (err, res) => {
71 | if (err) {
72 | reject(err);
73 | }
74 | assert.strictEqual(
75 | "worker-signature-with-signed-by-the-private-key-of-the-sender-key",
76 | res.result.result.workerSig,
77 | "workersig dont match"
78 | );
79 | await pMainController.shutdownSystem();
80 | await bMainController.shutdownSystem();
81 | pCoreServer.disconnect();
82 | bCoreServer.disconnect();
83 | resolve();
84 | });
85 | });
86 | });
87 | });
88 |
--------------------------------------------------------------------------------
/test/tasks/utils.js:
--------------------------------------------------------------------------------
1 | const ComputeTask = require("../../src/worker/tasks/ComputeTask");
2 | const DeployTask = require("../../src/worker/tasks/DeployTask");
3 | const Result = require("../../src/worker/tasks/Result");
4 | const testUtils = require("../testUtils/utils");
5 | const constants = require("../../src/common/constants");
6 | const deployTasks = require("./random_deploy_tasks.json");
7 | const computeTasks = require("./random_compute_tasks.json");
8 |
9 | function generateTasks(num, type) {
10 | const tasks = [];
11 | const taskType = type === "deploy" ? DeployTask : ComputeTask;
12 | const taskList = type === "deploy" ? deployTasks : computeTasks;
13 | for (let i = 0; i < num; i++) {
14 | const task = taskList[i];
15 | task.taskId = testUtils.randLenStr(64);
16 | tasks.push(taskType.fromDbJson(task));
17 | }
18 | return tasks;
19 | }
20 |
21 | generateComputeTasks = num => generateTasks(num, "compute");
22 |
23 | generateDeployTasks = num => generateTasks(num, "deploy");
24 |
25 | function generateBundle(num, isSuccess, type) {
26 | const tasks = type === "deploy" ? generateDeployTasks(num) : generateComputeTasks(num);
27 | const taskResult =
28 | type === "deploy" ? Result.DeployResult.buildDeployResult : Result.ComputeResult.buildComputeResult;
29 | return tasks.map(task => {
30 | let resObj = {
31 | taskId: task.getTaskId(),
32 | status: isSuccess ? constants.TASK_STATUS.SUCCESS : constants.TASK_STATUS.FAILED,
33 | output: testUtils.randLenStr(200),
34 | delta: { key: 0, data: testUtils.getRandomByteArray(20) },
35 | usedGas: testUtils.getRandomInt(10000),
36 | ethereumPayload: testUtils.getRandomByteArray(100),
37 | ethereumAddress: testUtils.randLenStr(40),
38 | signature: testUtils.getRandomByteArray(120),
39 | preCodeHash: testUtils.randLenStr(64),
40 | blockNumber: testUtils.getRandomInt(100)
41 | };
42 | return {
43 | task,
44 | result: isSuccess ? taskResult(resObj) : Result.FailedResult.buildFailedResult(resObj)
45 | };
46 | });
47 | }
48 |
49 | module.exports.generateComputeTasks = generateComputeTasks;
50 |
51 | module.exports.generateDeployTasks = generateDeployTasks;
52 |
53 | module.exports.generateDeployBundle = (num, isSuccess) => generateBundle(num, isSuccess, "deploy");
54 |
55 | module.exports.generateComputeBundle = (num, isSuccess) => generateBundle(num, isSuccess, "compute");
56 |
--------------------------------------------------------------------------------
/test/testUtils/id-d.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "Qma3GsJmB47xYuyahPZPSadh1avvxfyYQwk8R3UnFrQ6aP",
3 | "privKey": "CAASpwkwggSjAgEAAoIBAQCaNSDOjPz6T8HZsf7LDpxiQRiN2OjeyIHUS05p8QWOr3EFUCFsC31R4moihE5HN+FxNalUyyFZU//yjf1pdnlMJqrVByJSMa+y2y4x2FucpoCAO97Tx+iWzwlZ2UXEUXM1Y81mhPbeWXy+wP2xElTgIER0Tsn/thoA0SD2u9wJuVvM7dB7cBcHYmqV6JH+KWCedRTum6O1BssqP/4Lbm2+rkrbZ4+oVRoU2DRLoFhKqwqLtylrbuj4XOI3XykMXV5+uQXz1JzubNOB9lsc6K+eRC+w8hhhDuFMgzkZ4qomCnx3uhO67KaICd8yqqBa6PJ/+fBM5Xk4hjyR40bwcf41AgMBAAECggEAZnrCJ6IYiLyyRdr9SbKXCNDb4YByGYPEi/HT1aHgIJfFE1PSMjxcdytxfyjP4JJpVtPjiT9JFVU2ddoYu5qJN6tGwjVwgJEWg1UXmPaAw1T/drjS94kVsAs82qICtFmwp52Apg3dBZ0Qwq/8qE1XbG7lLyohIbfCBiL0tiPYMfkcsN9gnFT/kFCX0LVs2pa9fHCRMY9rqCc4/rWJa1w8sMuQ23y4lDaxKF9OZVvOHFQkbBDrkquWHE4r55fchCz/rJklkPJUNENuncBRu0/2X+p4IKFD1DnttXNwb8j4LPiSlLro1T0hiUr5gO2QmdYwXFF63Q3mjQy0+5I4eNbjjQKBgQDZvZy3gUKS/nQNkYfq9za80uLbIj/cWbO+ZZjXCsj0fNIcQFJcKMBoA7DjJvu2S/lf86/41YHkPdmrLAEQAkJ+5BBNOycjYK9minTEjIMMmZDTXXugZ62wnU6F46uLkgEChTqEP57Y6xwwV+JaEDFEsW5N1eE9lEVX9nGIr4phMwKBgQC1TazLuEt1WBx/iUT83ita7obXqoKNzwsS/MWfY2innzYZKDOqeSYZzLtt9uTtp4X4uLyPbYs0qFYhXLsUYMoGHNN8+NdjoyxCjQRJRBkMtaNR0lc5lVDWl3bTuJovjFCgAr9uqJrmI5OHcCIk/cDpdWb3nWaMihVlePmiTcTy9wKBgQCU0u7c1jKkudqks4XM6a+2HAYGdUBk4cLjLhnrUWnNAcuyl5wzdX8dGPi8KZb+IKuQE8WBNJ2VXVj7kBYh1QmSJVunDflQSvNYCOaKuOeRoxzD+y9Wkca74qkbBmPn/6FFEb7PSZTO+tPHjyodGNgz9XpJJRjQuBk1aDJtlF3m1QKBgE5SAr5ym65SZOU3UGUIOKRsfDW4Q/OsqDUImvpywCgBICaX9lHDShFFHwau7FA52ScL7vDquoMB4UtCOtLfyQYA9995w9oYCCurrVlVIJkb8jSLcADBHw3EmqF1kq3NqJqm9TmBfoDCh52vdCCUufxgKh33kfBOSlXuf7B8dgMbAoGAZ3r0/mBQX6S+s5+xCETMTSNv7TQzxgtURIpVs+ZVr2cMhWhiv+n0Omab9X9Z50se8cWl5lkvx8vn3D/XHHIPrMF6qk7RAXtvReb+PeitNvm0odqjFv0J2qki6fDs0HKwq4kojAXI1Md8Th0eobNjsy21fEEJT7uKMJdovI/SErI=",
4 | "pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaNSDOjPz6T8HZsf7LDpxiQRiN2OjeyIHUS05p8QWOr3EFUCFsC31R4moihE5HN+FxNalUyyFZU//yjf1pdnlMJqrVByJSMa+y2y4x2FucpoCAO97Tx+iWzwlZ2UXEUXM1Y81mhPbeWXy+wP2xElTgIER0Tsn/thoA0SD2u9wJuVvM7dB7cBcHYmqV6JH+KWCedRTum6O1BssqP/4Lbm2+rkrbZ4+oVRoU2DRLoFhKqwqLtylrbuj4XOI3XykMXV5+uQXz1JzubNOB9lsc6K+eRC+w8hhhDuFMgzkZ4qomCnx3uhO67KaICd8yqqBa6PJ/+fBM5Xk4hjyR40bwcf41AgMBAAE="
5 | }
6 |
--------------------------------------------------------------------------------
/test/testUtils/id-l.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "QmcrQZ6RJdpYuGvZqD5QEHAv6qX4BrQLJLQPQUrTrzdcgm",
3 | "privKey": "CAASqAkwggSkAgEAAoIBAQDLZZcGcbe4urMBVlcHgN0fpBymY+xcr14ewvamG70QZODJ1h9sljlExZ7byLiqRB3SjGbfpZ1FweznwNxWtWpjHkQjTVXeoM4EEgDSNO/Cg7KNlU0EJvgPJXeEPycAZX9qASbVJ6EECQ40VR/7+SuSqsdL1hrmG1phpIju+D64gLyWpw9WEALfzMpH5I/KvdYDW3N4g6zOD2mZNp5y1gHeXINHWzMF596O72/6cxwyiXV1eJ000k1NVnUyrPjXtqWdVLRk5IU1LFpoQoXZU5X1hKj1a2qt/lZfH5eOrF/ramHcwhrYYw1txf8JHXWO/bbNnyemTHAvutZpTNrsWATfAgMBAAECggEAQj0obPnVyjxLFZFnsFLgMHDCv9Fk5V5bOYtmxfvcm50us6ye+T8HEYWGUa9RrGmYiLweuJD34gLgwyzE1RwptHPj3tdNsr4NubefOtXwixlWqdNIjKSgPlaGULQ8YF2tm/kaC2rnfifwz0w1qVqhPReO5fypL+0ShyANVD3WN0Fo2ugzrniCXHUpR2sHXSg6K+2+qWdveyjNWog34b7CgpV73Ln96BWae6ElU8PR5AWdMnRaA9ucA+/HWWJIWB3Fb4+6uwlxhu2L50Ckq1gwYZCtGw63q5L4CglmXMfIKnQAuEzazq9T4YxEkp+XDnVZAOgnQGUBYpetlgMmkkh9qQKBgQDvsEs0ThzFLgnhtC2Jy//ZOrOvIAKAZZf/mS08AqWH3L0/Rjm8ZYbLsRcoWU78sl8UFFwAQhMRDBP9G+RPojWVahBL/B7emdKKnFR1NfwKjFdDVaoX5uNvZEKSl9UubbC4WZJ65u/cd5jEnj+w3ir9G8n+P1gp/0yBz02nZXFgSwKBgQDZPQr4HBxZL7Kx7D49ormIlB7CCn2i7mT11Cppn5ifUTrp7DbFJ2t9e8UNk6tgvbENgCKXvXWsmflSo9gmMxeEOD40AgAkO8Pn2R4OYhrwd89dECiKM34HrVNBzGoB5+YsAno6zGvOzLKbNwMG++2iuNXqXTk4uV9GcI8OnU5ZPQKBgCZUGrKSiyc85XeiSGXwqUkjifhHNh8yH8xPwlwGUFIZimnD4RevZI7OEtXw8iCWpX2gg9XGuyXOuKORAkF5vvfVriV4e7c9Ad4Igbj8mQFWz92EpV6NHXGCpuKqRPzXrZrNOA9PPqwSs+s9IxI1dMpk1zhBCOguWx2m+NP79NVhAoGBAI6WSoTfrpu7ewbdkVzTWgQTdLzYNe6jmxDf2ZbKclrf7lNr/+cYIK2Ud5qZunsdBwFdgVcnu/02czeS42TvVBgs8mcgiQc/Uy7yi4/VROlhOnJTEMjlU2umkGc3zLzDgYiRd7jwRDLQmMrYKNyEr02HFKFn3w8kXSzW5I8rISnhAoGBANhchHVtJd3VMYvxNcQb909FiwTnT9kl9pkjhwivx+f8/K8pDfYCjYSBYCfPTM5Pskv5dXzOdnNuCj6Y2H/9m2SsObukBwF0z5Qijgu1DsxvADVIKZ4rzrGb4uSEmM6200qjJ/9U98fVM7rvOraakrhcf9gRwuspguJQnSO9cLj6",
4 | "pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLZZcGcbe4urMBVlcHgN0fpBymY+xcr14ewvamG70QZODJ1h9sljlExZ7byLiqRB3SjGbfpZ1FweznwNxWtWpjHkQjTVXeoM4EEgDSNO/Cg7KNlU0EJvgPJXeEPycAZX9qASbVJ6EECQ40VR/7+SuSqsdL1hrmG1phpIju+D64gLyWpw9WEALfzMpH5I/KvdYDW3N4g6zOD2mZNp5y1gHeXINHWzMF596O72/6cxwyiXV1eJ000k1NVnUyrPjXtqWdVLRk5IU1LFpoQoXZU5X1hKj1a2qt/lZfH5eOrF/ramHcwhrYYw1txf8JHXWO/bbNnyemTHAvutZpTNrsWATfAgMBAAE="
5 | }
6 |
--------------------------------------------------------------------------------
/test/testUtils/principal_mock.js:
--------------------------------------------------------------------------------
1 | const jayson = require("jayson");
2 |
3 | /**
4 | * Creates a principal mock server
5 | * @param {Integer} getStateKeysCb
6 | * @return {Object} principal mock server
7 | * */
8 | module.exports.create = getStateKeysCb => {
9 | const server = jayson
10 | .server({
11 | getStateKeys: getStateKeysCb
12 | })
13 | .http()
14 | .setTimeout(500000);
15 | server.listen(0, "127.0.0.1");
16 | return server;
17 | };
18 |
19 | module.exports.destroy = server => {
20 | server.close();
21 | };
22 |
23 | module.exports.getPort = server => {
24 | return server.address().port;
25 | };
26 |
--------------------------------------------------------------------------------
/test/testUtils/utils.js:
--------------------------------------------------------------------------------
1 | var rimraf = require("rimraf");
2 | const randomize = require("randomatic");
3 |
4 | /**
5 | * Generate variable size random string from Aa0
6 | * @param {Integer} size
7 | * @return {string} result
8 | * */
9 | module.exports.randLenStr = function(size) {
10 | return randomize("Aa0", size);
11 | };
12 | /**
13 | * generate random integer with max
14 | * @param {Integer} max
15 | */
16 | module.exports.getRandomInt = function(max) {
17 | return _randomInt(max);
18 | };
19 |
20 | function _randomInt(max) {
21 | return Math.floor(Math.random() * Math.floor(max));
22 | }
23 |
24 | module.exports.getRandomByteArray = function(size) {
25 | let output = [];
26 | for (let i = 0; i < size; ++i) {
27 | output.push(_randomInt(256));
28 | }
29 | return output;
30 | };
31 |
32 | module.exports.sleep = function(ms) {
33 | return _sleep(ms);
34 | };
35 |
36 | function _sleep(ms) {
37 | return new Promise(resolve => setTimeout(resolve, ms));
38 | }
39 |
40 | module.exports.rm_Minus_Rf = async path => {
41 | return new Promise((resolve, reject) => {
42 | _deleteFolderFromOSRecursive(path, err => {
43 | if (err) reject(err);
44 | else resolve();
45 | });
46 | });
47 | };
48 |
49 | module.exports.deleteFolderFromOSRecursive = function(path, callback) {
50 | _deleteFolderFromOSRecursive(path, callback);
51 | };
52 |
53 | /**
54 | * same as rm -rf
55 | * @param {string} path
56 | * @param {function} callback
57 | */
58 | function _deleteFolderFromOSRecursive(path, callback) {
59 | rimraf(path, callback);
60 | }
61 |
--------------------------------------------------------------------------------
/test/test_tree.js:
--------------------------------------------------------------------------------
1 | module.exports.TEST_TREE = {
2 | basic: {
3 | all: true,
4 | "#1": true,
5 | "#2": true,
6 | "#3": true
7 | },
8 | ipc: {
9 | all: true,
10 | "#1": true,
11 | "#2": true,
12 | "#3": true,
13 | "#4": true,
14 | "#5": true,
15 | "#6": true
16 | },
17 | ethereum: {
18 | all: true,
19 | "#1": true,
20 | "#2": true,
21 | "#3": true,
22 | "#4": true,
23 | "#5": true,
24 | "#6": true,
25 | "#7": true,
26 | "#8": true,
27 | "#9": true,
28 | "#10": true,
29 | "#11": true,
30 | "#12": true,
31 | "#13": true,
32 | "#14": true,
33 | "#15": true,
34 | "#16": true,
35 | "#17": true,
36 | "#18": true,
37 | "#19": true
38 | },
39 | ethereum_advanced: {
40 | all: true,
41 | "#1": true,
42 | "#2": true,
43 | "#3": true,
44 | "#4": true
45 | },
46 | task_manager: {
47 | all: true,
48 | "#1": true,
49 | "#2": true,
50 | "#3": true,
51 | "#4": true,
52 | "#5": true,
53 | "#6": true
54 | },
55 | task_flow: {
56 | all: true,
57 | "#1": true,
58 | "#2": true,
59 | "#3": true,
60 | "#4": true
61 | },
62 | sync_basic: {
63 | all: true,
64 | "#1": true,
65 | "#2": true,
66 | "#3": true,
67 | "#4": true,
68 | "#5": true
69 | },
70 | sync_network: {
71 | all: true,
72 | "#1": true
73 | },
74 | jsonrpc_basic: {
75 | all: true,
76 | "#1": true,
77 | "#2": true,
78 | "#3": true,
79 | "#4": true,
80 | "#5": true,
81 | "#6": true
82 | },
83 | jsonrpc_advanced: {
84 | all: true,
85 | "#1": true,
86 | "#2": true,
87 | "#3": true,
88 | "#4": true
89 | },
90 | actions_tests: {
91 | all: true,
92 | "#1": true,
93 | "#2": true,
94 | "#3": true
95 | },
96 | principal: {
97 | all: true,
98 | "#1": true,
99 | "#2": true,
100 | "#3": true
101 | },
102 | verifier: {
103 | all: true,
104 | "#1": true,
105 | "#2": true,
106 | "#3": true,
107 | "#4": true,
108 | "#5": true,
109 | "#6": true,
110 | "#7": true,
111 | "#8": true,
112 | "#9": true,
113 | "#10": true,
114 | "#11": true,
115 | "#12": true,
116 | "#13": true,
117 | "#14": true,
118 | "#15": true,
119 | "#16": true,
120 | "#17": true,
121 | "#18": true,
122 | "#19": true,
123 | "#20": true,
124 | "#21": true,
125 | "#22": true,
126 | "#23": true,
127 | "#24": true,
128 | "#25": true,
129 | "#26": true,
130 | "#27": true,
131 | "#28": true,
132 | "#29": true,
133 | "#30": true,
134 | "#31": true,
135 | "#32": true,
136 | "#33": true,
137 | "#34": true,
138 | "#35": true,
139 | "#36": true,
140 | "#37": true,
141 | "#38": true,
142 | "#39": true,
143 | "#40": true,
144 | "#41": true,
145 | "#42": true,
146 | "#43": true,
147 | "#44": true,
148 | "#45": true,
149 | "#46": true,
150 | "#47": true,
151 | "#48": true
152 | },
153 | ethereum_integration: {
154 | all: true,
155 | "#1": true,
156 | "#2": true,
157 | "#3": true,
158 | "#4": true,
159 | "#5": true,
160 | "#6": true,
161 | "#7": true,
162 | "#8": true
163 | },
164 | single_config: {
165 | all: true,
166 | "#1": true,
167 | "#2": true
168 | },
169 | healthcheck: {
170 | all: true,
171 | "#1": true
172 | },
173 | init_worker: {
174 | all: true,
175 | "#1": true
176 | }
177 | };
178 |
--------------------------------------------------------------------------------
/test/webserver_test.js:
--------------------------------------------------------------------------------
1 | const assert = require("assert");
2 | const axios = require("axios");
3 | const testBuilder = require("./testUtils/quickBuilderUtil");
4 | const testUtils = require("./testUtils/utils");
5 | const constants = require("../src/common/constants");
6 | const tree = require("./test_tree").TEST_TREE.healthcheck;
7 |
8 | const noLoggerOpts = {
9 | bOpts: {
10 | withLogger: true
11 | },
12 | pOpts: {
13 | withLogger: true
14 | }
15 | };
16 |
17 | const stopTest = async (peers, bNodeController, bNodeCoreServer, resolve) => {
18 | const pPaths = peers.map(p => {
19 | return p.tasksDbPath;
20 | });
21 | try {
22 | for (let i = 0; i < pPaths.length; ++i) {
23 | await peers[i].mainController.shutdownSystem();
24 | peers[i].coreServer.disconnect();
25 | }
26 | await bNodeController.shutdownSystem();
27 | bNodeCoreServer.disconnect();
28 | } catch (e) {
29 | console.log("ERROR while trying to stop the nodes=" + JSON.stringify(e));
30 | }
31 | resolve();
32 | };
33 |
34 | it("#1 Query healthCheck + status", async function() {
35 | if (!tree["all"] || !tree["#1"]) {
36 | this.skip();
37 | }
38 | return new Promise(async resolve => {
39 | const peersNum = 5;
40 | const port = 9898;
41 | const hcUrl = "/hc";
42 | const statusUrl = "/st";
43 | // init nodes
44 | const { peers, bNode } = await testBuilder.createN(peersNum, noLoggerOpts);
45 | await testUtils.sleep(4000);
46 | const bNodeController = bNode.mainController;
47 | const bNodeCoreServer = bNode.coreServer;
48 | // start the tested node
49 | const testPeer = await testBuilder.createNode({
50 | withEth: true,
51 | ethWorkerAddress: "0xb9A219631Aed55eBC3D998f17C3840B7eC39C0cc",
52 | webserver: { port: port, healthCheck: { url: hcUrl }, status: { url: statusUrl } }
53 | });
54 |
55 | let connectedPeers = 0;
56 | testPeer.mainController
57 | .getNode()
58 | .engNode()
59 | .node.on(constants.PROTOCOLS.PEER_CONNECT, async peer => {
60 | connectedPeers += 1;
61 |
62 | // start test only after all connections established
63 | if (connectedPeers === peersNum + 1) {
64 | // request health check
65 | let url = "http://localhost:" + port + hcUrl;
66 | let response = await axios.get(url);
67 | assert.strictEqual(response.status, 200);
68 | assert.strictEqual(response.data.core.status, true);
69 | assert.strictEqual(response.data.core.registrationParams.signKey.length, 42);
70 | assert.strictEqual(response.data.ethereum.status, true);
71 | assert.strictEqual(response.data.connectivity.status, true);
72 | assert.strictEqual(response.data.connectivity.connections, peersNum + 1);
73 |
74 | // request status
75 | url = "http://localhost:" + port + statusUrl;
76 | response = await axios.get(url);
77 | assert.strictEqual(response.status, 200);
78 | assert.strictEqual(response.data, constants.WORKER_STATUS.UNREGISTERED);
79 |
80 | // STOP EVERYTHING
81 | peers.push(testPeer);
82 | await stopTest(peers, bNodeController, bNodeCoreServer, resolve);
83 | }
84 | });
85 | });
86 | });
87 |
--------------------------------------------------------------------------------