Skip to content

Commit

Permalink
Merge pull request #1 from Agoric/init
Browse files Browse the repository at this point in the history
init. Taken from SwingSet
  • Loading branch information
katelynsills authored Jun 5, 2019
2 parents 5b703fe + d577bd4 commit 87e3e10
Show file tree
Hide file tree
Showing 33 changed files with 5,164 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/dist
/src/bundles/
21 changes: 21 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* global module */
module.exports = {
extends: ['airbnb', 'plugin:prettier/recommended'],
env: {
es6: true, // supports new ES6 globals (e.g., new types such as Set)
},
rules: {
'implicit-arrow-linebreak': 'off',
'function-paren-newline': 'off',
'arrow-parens': 'off',
strict: 'off',
'no-console': 'off',
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'no-return-assign': 'off',
'no-param-reassign': 'off',
'no-restricted-syntax': ['off', 'ForOfStatement'],
'no-unused-expressions': 'off',
'no-loop-func': 'off',
'import/prefer-default-export': 'off', // contrary to Agoric standard
},
};
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# emacs
*~

# Logs
logs
*.log
Expand Down
15 changes: 15 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# demo
scripts

# non-applicable src
src/old
.misc

# embedded local package
agoric-evaluate/node_modules

# test
test

# Travis CI
.circleci
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Proposal Realms
/proposal-realms
4 changes: 4 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"trailingComma": "all",
"singleQuote": true
}
244 changes: 244 additions & 0 deletions core/assays.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
// Copyright (C) 2019 Agoric, under Apache License 2.0

import Nat from '@agoric/nat';
import harden from '@agoric/harden';

import { insist } from '../util/insist';
import {
sameStructure,
mustBeSameStructure,
mustBeComparable,
} from '../util/sameStructure';

// This assays.js module treats labels as black boxes. It is not aware
// of issuers, and so can handle labels whose issuers are merely
// presences of remote issuers.

// Return an assay, which makes amounts, validates amounts, and
// provides set operations over amounts. An amount is a pass-by-copy
// description of some set of erights. An amount has a label and a
// quantity. All amounts made by the same assay have the same label
// but differ in quantity.
//
// An assay is pass-by-presence, but is not designed to be usefully
// passed. Rather, we expect each vat that needs to operate on amounts
// will have its own local assay to do so.
//
// The default assay makes the default kind of amount. The default
// kind of amount is a labeled natural number describing a quantity of
// fungible erights. The label describes what kinds of rights these
// are. This is a form of labeled unit, as in unit typing.
function makeNatAssay(label) {
mustBeComparable(label);

// memoize well formedness check of amounts
const brand = new WeakSet();

const assay = harden({
getLabel() {
return label;
},

// Given the raw quantity that this kind of amount would label, return
// an amount so labeling that quantity.
make(allegedQuantity) {
const amount = harden({ label, quantity: Nat(allegedQuantity) });
brand.add(amount);
return amount;
},

// Is this an amount object made by this assay? If so, return
// it. Otherwise error.
vouch(amount) {
insist(brand.has(amount))`\
Unrecognized amount: ${amount}`;
return amount;
},

// Is this like an amount object made by this assay, such as one
// received by pass-by-copy from an otherwise-identical remote
// amount? On success, return an amount object made by this
// assay. Otherwise error.
//
// Until we have good support for pass-by-construction, the full
// assay style is too awkward to use remotely. See
// mintTestAssay. So coerce also accepts a bare number which it
// will coerce to a labeled number via assay.make.
coerce(allegedAmount) {
if (typeof allegedAmount === 'number') {
// Will throw on inappropriate number
return assay.make(allegedAmount);
}
if (brand.has(allegedAmount)) {
return allegedAmount;
}
const { label: allegedLabel, quantity } = allegedAmount;
mustBeSameStructure(label, allegedLabel, 'Unrecognized label');
// Will throw on inappropriate quantity
return assay.make(quantity);
},

// Return the raw quantity that this amount labels.
quantity(amount) {
return assay.vouch(amount).quantity;
},

// Represents the empty set of erights, i.e., no erights
empty() {
return assay.make(0);
},

isEmpty(amount) {
return assay.quantity(amount) === 0;
},

// Set inclusion of erights.
// Does the set of erights described by `leftAmount` include all
// the erights described by `rightAmount`?
includes(leftAmount, rightAmount) {
return assay.quantity(leftAmount) >= assay.quantity(rightAmount);
},

// Set union of erights.
// Describe all the erights described by `leftAmount` and those
// described by `rightAmount`.
with(leftAmount, rightAmount) {
return assay.make(
assay.quantity(leftAmount) + assay.quantity(rightAmount),
);
},

// Covering set subtraction of erights.
// If leftAmount does not include rightAmount, error.
// Describe the erights described by `leftAmount` and not described
// by `rightAmount`.
without(leftAmount, rightAmount) {
return assay.make(
assay.quantity(leftAmount) - assay.quantity(rightAmount),
);
},
});
return assay;
}
harden(makeNatAssay);

// A uniAssay makes uni amounts, which are either empty or have unique
// descriptions. The quantity must either be null, in which case it is
// empty, or be some truthy comparable value, in which case it
// represents a single unique unit described by that truthy
// quantity. Combining two uni amounts with different truthy
// quantities fails, as they represent non-combinable rights.
function makeUniAssayMaker(descriptionCoercer = d => d) {
function makeUniAssay(label) {
mustBeComparable(label);

const brand = new WeakSet();

const emptyAmount = harden({ label, quantity: null });
brand.add(emptyAmount);

const assay = harden({
getLabel() {
return label;
},

make(optDescription) {
if (optDescription === null) {
return emptyAmount;
}
insist(!!optDescription)`\
Uni optDescription must be either null or truthy ${optDescription}`;
mustBeComparable(optDescription);

const description = descriptionCoercer(optDescription);
insist(!!description)`\
Uni description must be truthy ${description}`;
mustBeComparable(description);

const amount = harden({ label, quantity: description });
brand.add(amount);
return amount;
},

vouch(amount) {
insist(brand.has(amount))`\
Unrecognized amount: ${amount}`;
return amount;
},

coerce(allegedMetaAmount) {
if (brand.has(allegedMetaAmount)) {
return allegedMetaAmount;
}
const { label: allegedLabel, quantity } = allegedMetaAmount;
mustBeSameStructure(label, allegedLabel, 'Unrecognized label');
return assay.make(quantity);
},

quantity(amount) {
return assay.vouch(amount).quantity;
},

empty() {
return emptyAmount;
},

isEmpty(amount) {
return assay.quantity(amount) === null;
},

includes(leftAmount, rightAmount) {
const leftQuant = assay.quantity(leftAmount);
const rightQuant = assay.quantity(rightAmount);
if (rightQuant === null) {
return true;
}
return sameStructure(leftQuant, rightQuant);
},

with(leftAmount, rightAmount) {
const leftQuant = assay.quantity(leftAmount);
const rightQuant = assay.quantity(rightAmount);
if (leftQuant === null) {
return rightAmount;
}
if (rightQuant === null) {
return leftAmount;
}
if (sameStructure(leftQuant, rightQuant)) {
// The "throw" is useless since insist(false) will unconditionally
// throw anyway. Rather, it informs IDEs of this control flow.
throw insist(false)`\
Even identical non-empty uni amounts cannot be added together ${leftAmount}`;
} else {
// The "throw" is useless since insist(false) will unconditionally
// throw anyway. Rather, it informs IDEs of this control flow.
throw insist(false)`\
Cannot combine different uni descriptions ${leftAmount} vs ${rightAmount}`;
}
},

without(leftAmount, rightAmount) {
const leftQuant = assay.quantity(leftAmount);
const rightQuant = assay.quantity(rightAmount);
if (rightQuant === null) {
return leftAmount;
}
insist(leftQuant !== null)`\
Empty left does not include ${rightAmount}`;

mustBeSameStructure(
leftQuant,
rightQuant,
'Cannot subtract different uni descriptions',
);
return emptyAmount;
},
});
return assay;
}
return harden(makeUniAssay);
}
harden(makeUniAssayMaker);

export { makeNatAssay, makeUniAssayMaker };
Loading

0 comments on commit 87e3e10

Please sign in to comment.