# Intro to Hardened JavaScript
_Status: WIP_.
---
## Intro to Hardened JavaScript
_Status: WIP_.
- JavaScript is popular
- JavaScript has some messy parts
- Stick to **Hardened JavaScript**
---
Overview
- Preface: Tools / Try it
- Objects
- Defensive Consistency
- **Electronic Rights**
- Reference: Data Structures, expressions, programs
---
## Try the Jessie linter (WIP!)
```bash
yarn add eslint @jessie.js/eslint-plugin
```
Then in `package.json`:
```json
"eslintConfig": {
"extends": [
"@jessie.js"
]
}
```
----
## Try the Jessie linter (WIP!)
At top of `myFile.js`:
```javascript
// @jessie-check
```
then run
```bash
yarn eslint --fix path/to/your-source.js
```
Edit based on advice in error messages; try again.
---
## Simple Objects
Singleton, stateless:
```javascript
const origin = {
getX: () => 0,
getY: () => 0,
};
```
```console
> origin.getY()
0
```
---
## Object makers
```javascript
const makeCounter = init => {
let value = init;
return {
increment: () => (value += 1),
decrement: () => (value -= 1),
makeOffsetCounter: delta => makeCounter(value + delta),
};
};
```
```javascript
$ node
Welcome to Node.js v14.16.0.
> const c1 = makeCounter(1); c1.increment();
2
> const c2 = c1.makeOffsetCounter(10);
> c2.increment();
13
> [c1.increment(), c2.increment()];
[ 3, 14 ]
```
---
## Object makers
```javascript
const makeCounter = init => {
let value = init;
return {
increment: () => (value += 1),
decrement: () => (value -= 1),
...
```
An object is a **record** of **functions** that close over **shared state**.
----
## Object makers: no `this`, `class`
```javascript
const makeCounter = init => {
let value = init;
return {
increment: () => (value += 1),
decrement: () => (value -= 1),
...
```
- The `this` keyword is not part of Jessie, so neither are constructors.
- A `makeCounter` function takes the place of the `class Counter` constructor syntax.
---
## WARNING: Pervasive Mutability
```javascript
> c1.increment = () => console.log('launch the missiles!');
[Function (anonymous)]
> c1.increment()
launch the missiles!
```
---
## Defensive objects with `harden()`
```javascript
const makeCounter = init => {
let value = init;
return harden({
increment: () => (value += 1),
decrement: () => (value -= 1),
makeOffsetCounter: delta => makeCounter(value + delta),
});
};
```
```javascript
> const c3 = Object.freeze(c1.makeOffsetCounter(10));
undefined
> c3.increment = () => { console.log('launch the missiles!'); }
TypeError: Cannot assign to read only property 'increment' of object '#<Object>'
> c3.increment()
15
```
----
## Defensive objects with `harden()`
- _caveat_: exception is thrown in strict mode. REPL might not throw.
- regardless, the object defended itself
- Jessie pre-defines `harden` (_as does Agoric smart contract framework_)
- see the `ses` [hardened Javascript package](https://github.com/endojs/endo/tree/master/packages/ses#harden) otherwise
---
## Types: advisory
```javascript
// @ts-check
/** @param {number} init */
const makeCounter = init => {
let value = init;
return {
increment: () => (value += 1),
decrement: () => (value -= 1),
/** @param {number} delta */
makeOffsetCounter: delta => makeCounter(value + delta),
};
};
```
- [TypeScript: Documentation \- Type Checking JavaScript Files](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html)
---
## Types: advisory (cont.)
If we're not careful, our clients can cause us to mis-behave:
```javascript
> const evil = makeCounter('poison')
> evil2.increment()
'poison1'
```
or worse:
```
> const evil2 = makeCounter({ valueOf: () => { console.log('launch the missiles!'); return 1; } });
> evil2.increment()
launch the missiles!
2
```
---
## Types: defensive
```javascript
/** @param {number | bignum} init */
const makeCounter = init => {
let value = Nat(init);
return harden({
increment: () => (value += 1n),
/** @param {number | bignum} delta */
makeOffsetCounter: delta => makeCounter(value + Nat(delta)),
});
};
```
```javascript
> makeCounter('poison')
Uncaught TypeError: poison is a string but must be a bigint or a number
```
---
## Defensive Consistency
A program is _defensively consistent_ if it will never provide incorrect service to its well behaved clients desspite arbitrary behavior of its other clients.
- [Miller 2006](http://www.erights.org/talks/thesis/markm-thesis.pdf)
---
## Details: Stay Tuned
- Ordinary programming in JavaScript follows in a later section
- Much overlap with Java, Python, C, etc.
_If you are **not** familiar with programming in some language, study details a bit and then come back here._
---
## Electronic Rights
[![Agoric \+ Protocol Labs // Higher\-order Smart Contracts across Chains \- Mark Miller](https://user-images.githubusercontent.com/150986/129462162-4599c0f4-8519-4a04-a707-88ef6e6044d7.png)
](https://youtu.be/iyuo0ymTt4g?t=1525)
[**Watch 8 min**](https://youtu.be/iyuo0ymTt4g?t=1525)
----
### Electonic Rights
**Watch**: [the mint pattern](https://youtu.be/iyuo0ymTt4g?t=1525),
an 8 minute segment starting at 25:00
```javascript
const makeMint = () => {
const ledger = makeWeakMap();
const issuer = harden({
makeEmptyPurse: () => mint.makePurse(0),
});
const mint = harden({
makePurse: initialBalance => {
const purse = harden({
getIssuer: () => issuer,
getBalance: () => ledger.get(purse),
deposit: (amount, src) => {
Nat(ledger.get(purse) + Nat(amount));
ledger.set(src, Nat(ledger.get(src) - amount));
ledger.set(purse, ledger.get(purse) + amount);
},
withdraw: amount => {
const newPurse = issuer.makeEmptyPurse();
newPurse.deposit(amount, purse);
return newPurse;
},
});
ledger.set(purse, initialBalance);
return purse;
},
});
return mint;
};
```
---
## Agoric JavaScript APIs
- [ERTP Introduction](https://agoric.com/documentation/getting-started/ertp-introduction.html#creating-assets-with-ertp)
- [Introduction to Zoe](https://agoric.com/documentation/getting-started/intro-zoe.html#what-is-zoe)
- [Remote object communication with E\(\)](https://agoric.com/documentation/guides/js-programming/eventual-send.html)
---
## DIY Data Structures
Using only the object patterns we have seen so far:
```javascript
const makeFlexList = () => {
let head;
let tail;
const list = harden({
push: item => {
const cell = { item, next: undefined, previous: tail };
tail = cell;
if (head === undefined) {
head = cell;
}
},
at: target => {
if (!Number.isInteger(target) || target < 0) {
throw RangeError(target);
}
const position = 0;
for (let cell = head; cell !== undefined; cell = cell.next) {
if (position === target) {
return cell.item;
}
position += 1;
}
return undefined;
},
forEach: f => {
let position = 0;
for (let cell = head; cell !== undefined; cell = cell.next) {
f(cell.item, position, list);
position += 1;
}
return false;
},
});
return list;
};
```
_TODO: harden the cells? They don't escape, so technically we don't need to._
---
## Built-in Data Structures: Array
- syntax: `[...]` expressions
- built-in `Array` objects
- methods: `indexOf`, `reverse`, `sort`, ...
- full API: [Array in MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
---
## `Array` and `harden`
**WARNING: mutable by default**:
```javascript
const makeGame = (...players) => {
// TODO: harden(players)
return harden({
playing: () => players,
});
};
```
Game creator:
```javascript
> const g1 = makeGame('alice', 'bob');
```
Malicious client:
```javascript
> const who = g1.playing();
> who.push('mallory'); g1.playing()
[ 'alice', 'bob', 'mallory' ]
```
So we `harden(players)` before we `return ...`:
```javascript
> who.push('mallory');
Uncaught TypeError: Cannot add property 2, object is not extensible
```
---
## Built-in Data Structures: Map
`m.set(key, value)`, `m.get(key)`, `m.has(key)`:
```javascript
> const m1 = makeMap([['alice', 1], ['bob', 2], ['charlie', 3]])
Map(3) { 'alice' => 1, 'bob' => 2, 'charlie' => 3 }
> m1.has('bob')
true
> m1.get('charlie')
3
> m1.set('dave', 'pickles')
Map(4) {
'alice' => 1,
'bob' => 2,
'charlie' => 3,
'dave' => 'pickles'
}
```
Full API: [Map \- JavaScript \| MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
**NOTE:** `makeMap()` is a Jessie library function
because `new Map()` is not included in Jessie.
---
## Built-in Data Structures: Set
`s.delete(key)`, `s.size`: (_also on `Map`_)
```javascript
> const s1 = makeSet([1, 2, 3]);
Set(3) { 1, 2, 3 }
> s1.has(2)
true
> s1.delete(2)
true
> s1.size
2
> [...s1]
[ 1, 3 ]
```
Full API: [Set \- JavaScript \| MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
---
## Reference: JSON for Data
JSON is a ubiquitous language for structured data:
- Literals:
- `1, 2, 3, true, false, "abc", null`
- `"emoji: \uD83D\uDC36"`, `"🐶"`
- Array: `[1, true, "three"]`
- Record (aka Object): `{ "size": 5, "color": "blue" }`
---
## Reference: Justin for Safe Expressions
- more flexible syntax:
- string delimiters: `"abc"` or `'abc'`
- trailing commas: `{ size: 1, }`, `[1, 2, 3,]`
- un-quoted property names: `{ size: 1, color: "blue" }`
- short-hand properties: `{ size }`
- comments:
- single line: `// ...`
- multi-line: `/* ... */`
- property lookup: `{ size: 1 }.size`
- array index: `[1, 2, 3][2]`
---
## Justin: both bottom values (**:-/**)
- `null`
- `undefined`
---
## Justin: function and variable use
In an environment with pre-declared variables:
- variable use: `x`
- excludes reserved words / keywords: `if`, `else`, ...
- function call: `sqrt(2)`, `inventory.total()`
- spread: `sum(1, 2, ...rest)`, `{ color: 'red', ...options }`
---
## Justin: Quasi-Literals
- interpolation: `` `the answer is: ${a}` ``
- tagged templates: ``html`<a href=${url}>${linkText}</a>` ``
---
## Justin: operators
- add, subtract, etc.: `+`, `-`, `*`, `/`, `%`
- parens `(x + 4) * y`
- comparison: `===`, `!==`, `<`, `>`, `<=`, `>=`
- **no `==`!**
- relational: `&&`, `||`
- bitwise: `&`, `|`, `^`
- shift: `<<`, `>>`
- unsigned: `>>>`
- runtime type check: `typeof thing === "string"`
- conditional (ternary operator): ``a > b ? a : b``
- void operator: `void ignoreMyResult()`
---
## Jessie: operators
- pre-increment, decrement: `++x`, `--x`
- post-increment, decrement: `x++`, `x--`
---
## Reference: Jessie for simple, universal safe mobile code
statements, declarations:
- end with `;`
- arrow functions:
- simple: `const double = x => x * 2;`
- compound:
```javascript
const f = (a, b) => {
g(a);
h(b);
return a + b;
};
```
- bindings: `const c = a + b;`, `let x = 1;`
- assignment: `x = x + 2`;
- combined: `x += 2`;
- `if (cond) { /* then block */ } else { /* else block */ }`
- `switch`:
```javascript
switch (value) {
case 'a':
case 'b': {
/* 'a' and 'b' block */
break;
}
default: {
/* default block */
}
}
```
- `while (condition) { /* body */ }`
- `break`, `continue`
- `try` / `catch` / `finally`
- `for (const x of items) { /* body */ }`
- **no `for (const x in items)`!** Use `for (const x of Object.keys(items))` instead
_TODO: accessor methods?_
---
## Destructuring Assignments, Patterns, and Shorthand Properties
```javascript
const s = order.size; // better as...
const { size: s } = order;
const size = order.size; // better as...
const { size } = order;
const s1 = sizes[0];
const s2 = sizes[1];
const rest = sizes.slice(2); // better as...
const [s1, s2, ...rest] = sizes;
// combine them and go nuts
const [{ size: s1, color, ...details }, { size: s2 }] = orders;
```
---
## Parameters: destructuring, optional, defaults
```javascript
const serviceOrder = ({ size, shape }) => {
...
};
```
```javascript
const f = (a, opt) => {
if (typeof opt !== 'undefined') {
...
}
};
```
```javascript
const f = (a, b = 0) => {
}
```
_TODO: examples that concretely motivate these features_
---
## Modules
- import:
- `import harden from '@agoric/harden';`
- `import { Nat } from '@agoric/nat';`
- `import { Nat as N } from '@agoric/nat';`
- `import * as fs from 'fs';`
- export:
- `export const f = ...`;
- `export default f;`
- `export { f, g, h};`
---
## Appendix / Colophon: Fodder / Brainstorm
- structure from [E in a Walnut](http://www.skyhunter.com/marcs/ewalnut.html#SEC8)
- as adapted in [Practical Security: The Mafia game — Monte 0\.1 documentation](https://monte.readthedocs.io/en/latest/ordinary-programming.html)
- JSON / Justin / Jessie as in [Jessica](https://github.com/agoric-labs/jessica)
- Build slides with [Remark](https://remarkjs.com/#1)
- example: [kumc\-bmi/naaccr\-tumor\-data](https://github.com/kumc-bmi/naaccr-tumor-data)
_TODO: facets_
{"metaMigratedAt":"2023-06-16T10:31:15.121Z","metaMigratedFrom":"YAML","title":"Intro to Hardened JavaScript","breaks":"true","slideOptions":"{\"theme\":\"sky\",\"previewLinks\":true}","contributors":"[{\"id\":\"cb157d25-12e4-4439-9995-d4ad60a29bee\",\"add\":239,\"del\":404},{\"id\":\"64595b09-a475-434e-94cc-793ab5c9f676\",\"add\":15059,\"del\":1334}]"}