Skip to content

Commit 5f33a96

Browse files
authored
[demo] Lint More Files (#127)
* Add linting files. * Install an older version of eslint so that it's compatible with the one in the client folder. * Add some manual testing steps. * Make minor clean-ups in setup scripts. * README: Make minor clarifications.
1 parent af3eab1 commit 5f33a96

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+7208
-5930
lines changed

demo/.eslintignore

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
build/
2+
node_modules/
3+
dist/
4+
coverage/
5+
6+
# Client
7+
client/build/
8+
client/node_modules/
9+
client/dist/
10+
client/coverage/

demo/.eslintrc.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
module.exports = {
2+
root: true,
3+
env: {
4+
browser: true,
5+
node: true,
6+
es6: true,
7+
},
8+
parser: '@typescript-eslint/parser',
9+
plugins: [
10+
'@typescript-eslint',
11+
],
12+
extends: [
13+
'eslint:recommended',
14+
'plugin:@typescript-eslint/recommended',
15+
'plugin:react/recommended',
16+
],
17+
rules: {
18+
'@typescript-eslint/no-explicit-any': 'off',
19+
'@typescript-eslint/no-non-null-assertion': 'off',
20+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: "^_" }],
21+
// Messes up .js files.
22+
'@typescript-eslint/no-var-requires': 'off',
23+
'@typescript-eslint/type-annotation-spacing': ['error'],
24+
'array-bracket-spacing': ['error', 'never'],
25+
'arrow-spacing': ['error'],
26+
'comma-dangle': ['off', 'ignore'],
27+
'comma-spacing': ['error', { before: false, after: true }],
28+
indent: ['error', 'tab', { SwitchCase: 1 }],
29+
'key-spacing': ['error'],
30+
'keyword-spacing': ['error'],
31+
'no-tabs': 0,
32+
'object-curly-spacing': ['error', 'always'],
33+
'operator-linebreak': ['off'],
34+
quotes: ['off'],
35+
semi: ['error', 'never'],
36+
'space-before-function-paren': [2, {
37+
named: 'never',
38+
anonymous: 'always',
39+
asyncArrow: 'always'
40+
}],
41+
'space-in-parens': ['error', 'never'],
42+
'space-infix-ops': ['error', { int32Hint: false }],
43+
},
44+
}

demo/README.md

+43-12
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,25 @@ This section explains how to set up locally on Linux/WSL, alternatively, you can
1818
The following steps are made for Linux/WSL and require `npm` with `node` version 10.
1919
Other later versions of node might work too but some node-gyp issues occurred with version 14.
2020

21+
You will need to have `make` installed.
22+
On Debian (e.g. Ubuntu) you can do:
23+
```bash
24+
sudo apt install build-essential
25+
```
26+
2127
Run
2228
```bash
2329
./setup.sh
2430
```
2531

32+
## Troubleshooting Setup
33+
If you have problems running the setup steps related to node-gyp, then you might need to set Python 2.7 to be your default (just during the installation).
34+
Recommendation: Temporarily set up a Python 2.7 Conda environment (just for the installation) and activate it:
35+
```bash
36+
conda create --name python2 python=2
37+
conda activate python2
38+
```
39+
2640
## Docker Setup
2741
1. Clone this repo.
2842

@@ -69,9 +83,6 @@ docker push 0xdeca10bcontainerreg.azurecr.io/public/samples/blockchain-ai/0xdeca
6983

7084
(Microsoft Devs) To update the production website, see the instructions at the top of [service.Dockerfile](./service.Dockerfile).
7185

72-
## Troubleshooting Setup
73-
If you have problems running the setup steps related to node-gyp, then you might need to set Python 2.7 to be your default. Recommendation: Set up a Python 2.7 Conda environment and activate it.
74-
7586
## Update
7687
To update dependencies after already setting up:
7788
```bash
@@ -82,7 +93,10 @@ To update dependencies after already setting up:
8293
There is a video example showing how to deploy <a href="https://aka.ms/0xDeCA10B-deploy" target="_blank">here</a>.
8394

8495
## Blockchain
85-
Start the blockchain (Ganache) in one terminal.
96+
Models and data are stored on a local blockchain.
97+
98+
99+
Start the blockchain (uses `ganache-cli`) in one terminal.
86100
Run:
87101
```bash
88102
yarn blockchain
@@ -95,7 +109,9 @@ Do once:
95109
* Use that private key to create a new account in MetaMask.
96110

97111
## Server
98-
This is used by default in development mode but not in production.
112+
(Optional) The server is used to store model meta-data and original data when for training models.
113+
114+
The server is used by default in development mode but not in production mode.
99115

100116
If you want to store meta-data in a local database file instead of just within the browser, then start the server in one terminal.
101117
This step allows you to see models listed when you open the dashboard for the first time.
@@ -108,7 +124,9 @@ yarn server
108124
```
109125

110126
## Client
111-
Then in another terminal.
127+
The website is the "client", it allows you to interract with the blockchain and optional server.
128+
129+
In another terminal.
112130
Run:
113131
```bash
114132
yarn client
@@ -156,13 +174,25 @@ If you get the spinning issue again, then also try following the steps above wit
156174
[truffle-react]: https://truffleframework.com/boxes/react
157175

158176
# Testing
159-
To simply run all tests:
177+
To run all automated tests:
160178
```bash
161179
yarn test
162180
```
163181

164182
A local blockchain will be started and stopped so it's best not to have a blockchain running at the same address and port (e.g. one running through `yarn blockchain`).
165183

184+
## Manual Testing
185+
Not all tests are automated (yet, maybe one we'll automate them all).
186+
Some things that should be manually tested in the UI after completing the deployment:
187+
* Pick a model
188+
* PREDICT: Verify that you can use the model to classify some data
189+
* TRAIN: Add "incorrect" data as user "Bad"
190+
* Add "correct" data as user "Good"
191+
* REFUND: Verify that "Good" can get a refund for the "correct" data
192+
* REWARD: Verify that "Good" can report "Bad"'s "incorrect" data
193+
* Add a new model
194+
195+
166196
## Running Specific Tests
167197
To run specific smart contract tests and save time by not waiting for Truffle migrations:
168198
* In one terminal, start a blockchain: `yarn blockchain`
@@ -175,12 +205,13 @@ npx truffle test test/contracts/*.js test/contracts/**/*.js --network skipMigrat
175205
```
176206

177207
# Linting
178-
### Solidity Files
208+
Run `yarn lint`.
209+
210+
Run `yarn lint-fix` to automatically resolve some issues.
211+
212+
## Solidity Files
179213
We use [Ethlint][ethlint] for linting and enforce it on pull requests.
180-
To check the contract code run:
181-
```bash
182-
yarn lint
183-
```
214+
The above `yarn lint` and `yarn lint-fix` commands will also check Solidity files.
184215

185216
[deploy-video]: https://aka.ms/0xDeCA10B-deploy
186217
[demo-video]: https://aka.ms/0xDeCA10B-demo
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
var Migrations = artifacts.require("./Migrations.sol");
1+
var Migrations = artifacts.require("./Migrations.sol")
22

3-
module.exports = function(deployer) {
4-
deployer.deploy(Migrations);
5-
};
3+
module.exports = function (deployer) {
4+
deployer.deploy(Migrations)
5+
}

demo/client/migrations/2_deploy_sentiment_classifier.js

+84-84
Original file line numberDiff line numberDiff line change
@@ -4,95 +4,95 @@ const fs = require('fs')
44
const pjson = require('../package.json')
55
const { convertData, convertNum } = require('../src/float-utils-node.js')
66

7-
const CollaborativeTrainer64 = artifacts.require("./CollaborativeTrainer64");
8-
const DataHandler64 = artifacts.require("./data/DataHandler64");
9-
const Classifier = artifacts.require("./classification/SparsePerceptron");
10-
const Stakeable64 = artifacts.require("./incentive/Stakeable64");
7+
const CollaborativeTrainer64 = artifacts.require("./CollaborativeTrainer64")
8+
const DataHandler64 = artifacts.require("./data/DataHandler64")
9+
const Classifier = artifacts.require("./classification/SparsePerceptron")
10+
const Stakeable64 = artifacts.require("./incentive/Stakeable64")
1111

1212
module.exports = async function (deployer) {
13-
if (deployer.network === 'skipMigrations') {
14-
return;
15-
}
16-
// Information to persist to the database.
17-
const name = "IMDB Review Sentiment Classifier"
18-
const description = "A simple IMDB sentiment analysis model."
19-
const encoder = 'IMDB vocab'
20-
const modelInfo = {
21-
name,
22-
description,
23-
accuracy: '0.829',
24-
modelType: 'Classifier64',
25-
encoder,
26-
};
13+
if (deployer.network === 'skipMigrations') {
14+
return
15+
}
16+
// Information to persist to the database.
17+
const name = "IMDB Review Sentiment Classifier"
18+
const description = "A simple IMDB sentiment analysis model."
19+
const encoder = 'IMDB vocab'
20+
const modelInfo = {
21+
name,
22+
description,
23+
accuracy: '0.829',
24+
modelType: 'Classifier64',
25+
encoder,
26+
}
2727

28-
const toFloat = 1E9;
28+
const toFloat = 1E9
2929

30-
// Low default times for testing.
31-
const refundTimeS = 15;
32-
const anyAddressClaimWaitTimeS = 20;
33-
const ownerClaimWaitTimeS = 20;
34-
// Weight for deposit cost in wei.
35-
const costWeight = 1E15;
30+
// Low default times for testing.
31+
const refundTimeS = 15
32+
const anyAddressClaimWaitTimeS = 20
33+
const ownerClaimWaitTimeS = 20
34+
// Weight for deposit cost in wei.
35+
const costWeight = 1E15
3636

37-
const data = fs.readFileSync('./src/ml-models/imdb-sentiment-model.json', 'utf8');
38-
const model = JSON.parse(data);
39-
const { classifications } = model;
40-
const weights = convertData(model.weights, web3, toFloat);
41-
const initNumWords = 250;
42-
const numWordsPerUpdate = 250;
37+
const data = fs.readFileSync('./src/ml-models/imdb-sentiment-model.json', 'utf8')
38+
const model = JSON.parse(data)
39+
const { classifications } = model
40+
const weights = convertData(model.weights, web3, toFloat)
41+
const initNumWords = 250
42+
const numWordsPerUpdate = 250
4343

44-
console.log(`Deploying IMDB model with ${weights.length} weights.`);
45-
const intercept = convertNum(model.intercept || model.bias, web3, toFloat);
46-
const learningRate = convertNum(model.learningRate, web3, toFloat);
44+
console.log(`Deploying IMDB model with ${weights.length} weights.`)
45+
const intercept = convertNum(model.intercept || model.bias, web3, toFloat)
46+
const learningRate = convertNum(model.learningRate, web3, toFloat)
4747

48-
console.log(`Deploying DataHandler.`);
49-
return deployer.deploy(DataHandler64).then(dataHandler => {
50-
console.log(` Deployed data handler to ${dataHandler.address}.`);
51-
return deployer.deploy(Stakeable64,
52-
refundTimeS,
53-
ownerClaimWaitTimeS,
54-
anyAddressClaimWaitTimeS,
55-
costWeight
56-
).then(incentiveMechanism => {
57-
console.log(` Deployed incentive mechanism to ${incentiveMechanism.address}.`);
58-
console.log(`Deploying classifier.`);
59-
return deployer.deploy(Classifier,
60-
classifications, weights.slice(0, initNumWords), intercept, learningRate,
61-
{ gas: 7.9E6 }).then(async classifier => {
62-
console.log(` Deployed classifier to ${classifier.address}.`);
63-
for (let i = initNumWords; i < weights.length; i += numWordsPerUpdate) {
64-
await classifier.initializeWeights(i, weights.slice(i, i + numWordsPerUpdate),
65-
{ gas: 7.9E6 });
66-
console.log(` Added ${i + numWordsPerUpdate} weights.`);
67-
}
48+
console.log(`Deploying DataHandler.`)
49+
return deployer.deploy(DataHandler64).then(dataHandler => {
50+
console.log(` Deployed data handler to ${dataHandler.address}.`)
51+
return deployer.deploy(Stakeable64,
52+
refundTimeS,
53+
ownerClaimWaitTimeS,
54+
anyAddressClaimWaitTimeS,
55+
costWeight
56+
).then(incentiveMechanism => {
57+
console.log(` Deployed incentive mechanism to ${incentiveMechanism.address}.`)
58+
console.log(`Deploying classifier.`)
59+
return deployer.deploy(Classifier,
60+
classifications, weights.slice(0, initNumWords), intercept, learningRate,
61+
{ gas: 7.9E6 }).then(async classifier => {
62+
console.log(` Deployed classifier to ${classifier.address}.`)
63+
for (let i = initNumWords; i < weights.length; i += numWordsPerUpdate) {
64+
await classifier.initializeWeights(i, weights.slice(i, i + numWordsPerUpdate),
65+
{ gas: 7.9E6 })
66+
console.log(` Added ${i + numWordsPerUpdate} weights.`)
67+
}
6868

69-
console.log(`Deploying collaborative trainer contract.`);
70-
return deployer.deploy(CollaborativeTrainer64,
71-
name, description, encoder,
72-
dataHandler.address,
73-
incentiveMechanism.address,
74-
classifier.address
75-
).then(instance => {
76-
console.log(` Deployed IMDB collaborative classifier to ${instance.address}.`);
77-
return Promise.all([
78-
dataHandler.transferOwnership(instance.address),
79-
incentiveMechanism.transferOwnership(instance.address),
80-
classifier.transferOwnership(instance.address),
81-
]).then(() => {
82-
modelInfo.address = instance.address;
83-
return axios.post(`${pjson.proxy}api/models`, modelInfo).then(() => {
84-
console.log("Added model to the database.");
85-
}).catch(err => {
86-
if (process.env.CI !== "true" && process.env.REACT_APP_ENABLE_SERVICE_DATA_STORE === 'true') {
87-
// It is okay to fail adding the model in CI but otherwise it should work.
88-
console.error("Error adding model to the database.");
89-
console.error(err);
90-
throw err;
91-
}
92-
});
93-
});
94-
});
95-
});
96-
});
97-
});
98-
};
69+
console.log(`Deploying collaborative trainer contract.`)
70+
return deployer.deploy(CollaborativeTrainer64,
71+
name, description, encoder,
72+
dataHandler.address,
73+
incentiveMechanism.address,
74+
classifier.address
75+
).then(instance => {
76+
console.log(` Deployed IMDB collaborative classifier to ${instance.address}.`)
77+
return Promise.all([
78+
dataHandler.transferOwnership(instance.address),
79+
incentiveMechanism.transferOwnership(instance.address),
80+
classifier.transferOwnership(instance.address),
81+
]).then(() => {
82+
modelInfo.address = instance.address
83+
return axios.post(`${pjson.proxy}api/models`, modelInfo).then(() => {
84+
console.log("Added model to the database.")
85+
}).catch(err => {
86+
if (process.env.CI !== "true" && process.env.REACT_APP_ENABLE_SERVICE_DATA_STORE === 'true') {
87+
// It is okay to fail adding the model in CI but otherwise it should work.
88+
console.error("Error adding model to the database.")
89+
console.error(err)
90+
throw err
91+
}
92+
})
93+
})
94+
})
95+
})
96+
})
97+
})
98+
}

0 commit comments

Comments
 (0)