@agoric/solo 0.9.5 → 0.9.6-dev-800c2bb.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +2 -1
- package/jsconfig.json +2 -14
- package/package.json +29 -28
- package/public/main.js +1 -1
- package/solo-config.json +6 -1
- package/src/add-chain.js +3 -4
- package/src/captp.js +5 -8
- package/src/chain-cosmos-sdk.js +32 -35
- package/src/entrypoint.js +0 -3
- package/src/outbound.js +3 -3
- package/src/pipe-entrypoint.js +1 -2
- package/src/pipe.js +1 -1
- package/src/reset-state.js +1 -1
- package/src/start.js +35 -37
- package/src/vat-http.js +3 -17
- package/src/vat-uploads.js +2 -2
- package/src/web.js +12 -7
- package/test/captp-fixture.js +2 -2
- package/test/test-home.js +25 -13
- package/src/scratch.js +0 -53
package/Dockerfile
CHANGED
package/jsconfig.json
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
1
|
// This file can contain .js-specific Typescript compiler config.
|
|
2
2
|
{
|
|
3
|
+
"extends": "../../tsconfig.json",
|
|
3
4
|
"compilerOptions": {
|
|
4
|
-
"
|
|
5
|
-
"module": "esnext",
|
|
6
|
-
|
|
7
|
-
"noEmit": true,
|
|
8
|
-
/*
|
|
9
|
-
// The following flags are for creating .d.ts files:
|
|
10
|
-
"noEmit": false,
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"emitDeclarationOnly": true,
|
|
13
|
-
*/
|
|
14
|
-
"downlevelIteration": true,
|
|
15
|
-
"strictNullChecks": true,
|
|
16
|
-
"moduleResolution": "node",
|
|
5
|
+
"checkJs": false,
|
|
17
6
|
},
|
|
18
7
|
"include": [
|
|
19
|
-
"exported.js",
|
|
20
8
|
"public/**/*.js",
|
|
21
9
|
"src/**/*.js",
|
|
22
10
|
"test/**/*.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/solo",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.6-dev-800c2bb.0+800c2bb",
|
|
4
4
|
"description": "Agoric's Solo vat runner",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,39 +15,40 @@
|
|
|
15
15
|
"test:xs": "exit 0",
|
|
16
16
|
"lint-fix": "yarn lint:eslint --fix",
|
|
17
17
|
"lint": "run-s --continue-on-error lint:*",
|
|
18
|
-
"lint:types": "tsc
|
|
18
|
+
"lint:types": "tsc -p jsconfig.json",
|
|
19
19
|
"lint:eslint": "eslint ."
|
|
20
20
|
},
|
|
21
21
|
"keywords": [],
|
|
22
22
|
"author": "Agoric",
|
|
23
23
|
"license": "Apache-2.0",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@agoric/access-token": "
|
|
26
|
-
"@agoric/assert": "
|
|
27
|
-
"@agoric/cache": "
|
|
28
|
-
"@agoric/cosmic-swingset": "
|
|
29
|
-
"@agoric/
|
|
30
|
-
"@agoric/
|
|
31
|
-
"@agoric/
|
|
32
|
-
"@agoric/
|
|
33
|
-
"@agoric/
|
|
34
|
-
"@agoric/
|
|
35
|
-
"@agoric/
|
|
36
|
-
"@agoric/
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
39
|
-
"@endo/
|
|
40
|
-
"@endo/
|
|
41
|
-
"@endo/
|
|
42
|
-
"@endo/
|
|
43
|
-
"
|
|
25
|
+
"@agoric/access-token": "0.4.21-dev-800c2bb.0+800c2bb",
|
|
26
|
+
"@agoric/assert": "0.5.2-dev-800c2bb.0+800c2bb",
|
|
27
|
+
"@agoric/cache": "0.2.5-dev-800c2bb.0+800c2bb",
|
|
28
|
+
"@agoric/cosmic-swingset": "0.40.1-dev-800c2bb.0+800c2bb",
|
|
29
|
+
"@agoric/internal": "0.2.2-dev-800c2bb.0+800c2bb",
|
|
30
|
+
"@agoric/notifier": "0.5.2-dev-800c2bb.0+800c2bb",
|
|
31
|
+
"@agoric/spawner": "0.6.6-dev-800c2bb.0+800c2bb",
|
|
32
|
+
"@agoric/store": "0.8.6-dev-800c2bb.0+800c2bb",
|
|
33
|
+
"@agoric/swing-store": "0.8.2-dev-800c2bb.0+800c2bb",
|
|
34
|
+
"@agoric/swingset-vat": "0.31.1-dev-800c2bb.0+800c2bb",
|
|
35
|
+
"@agoric/telemetry": "0.5.1-dev-800c2bb.0+800c2bb",
|
|
36
|
+
"@agoric/time": "0.2.2-dev-800c2bb.0+800c2bb",
|
|
37
|
+
"@agoric/vats": "0.13.3-dev-800c2bb.0+800c2bb",
|
|
38
|
+
"@agoric/wallet": "0.17.3-dev-800c2bb.0+800c2bb",
|
|
39
|
+
"@endo/captp": "^3.1.1",
|
|
40
|
+
"@endo/eventual-send": "^0.17.2",
|
|
41
|
+
"@endo/import-bundle": "^0.3.4",
|
|
42
|
+
"@endo/init": "^0.5.56",
|
|
43
|
+
"@endo/marshal": "^0.8.5",
|
|
44
|
+
"@endo/promise-kit": "^0.2.56",
|
|
45
|
+
"agoric": "0.18.5-dev-800c2bb.0+800c2bb",
|
|
44
46
|
"anylogger": "^0.21.0",
|
|
45
47
|
"deterministic-json": "^1.0.5",
|
|
46
48
|
"esm": "agoric-labs/esm#Agoric-built",
|
|
47
49
|
"express": "^4.17.1",
|
|
48
50
|
"http-proxy-middleware": "^2.0.6",
|
|
49
|
-
"import-meta-resolve": "^
|
|
50
|
-
"lmdb": "^2.4.5",
|
|
51
|
+
"import-meta-resolve": "^2.2.1",
|
|
51
52
|
"minimist": "^1.2.0",
|
|
52
53
|
"morgan": "^1.9.1",
|
|
53
54
|
"node-fetch": "^2.6.0",
|
|
@@ -56,10 +57,10 @@
|
|
|
56
57
|
"ws": "^7.2.0"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
59
|
-
"@agoric/ertp": "
|
|
60
|
-
"@endo/bundle-source": "^2.
|
|
61
|
-
"ava": "^
|
|
62
|
-
"c8": "^7.
|
|
60
|
+
"@agoric/ertp": "0.15.6-dev-800c2bb.0+800c2bb",
|
|
61
|
+
"@endo/bundle-source": "^2.5.1",
|
|
62
|
+
"ava": "^5.2.0",
|
|
63
|
+
"c8": "^7.13.0"
|
|
63
64
|
},
|
|
64
65
|
"publishConfig": {
|
|
65
66
|
"access": "public"
|
|
@@ -74,5 +75,5 @@
|
|
|
74
75
|
"timeout": "20m",
|
|
75
76
|
"workerThreads": false
|
|
76
77
|
},
|
|
77
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "800c2bbed8ccb1e0fc24481c9f95027f95efc1fb"
|
|
78
79
|
}
|
package/public/main.js
CHANGED
package/solo-config.json
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
"bootstrap": "bootstrap",
|
|
3
3
|
"defaultManagerType": "xs-worker",
|
|
4
4
|
"defaultReapInterval": 1000,
|
|
5
|
+
"bundles":{
|
|
6
|
+
"agoricNames": {
|
|
7
|
+
"sourceSpec": "@agoric/vats/src/vat-agoricNames.js"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
5
10
|
"vats": {
|
|
6
11
|
"spawner": {
|
|
7
12
|
"sourceSpec": "./src/vat-spawner.js"
|
|
@@ -16,7 +21,7 @@
|
|
|
16
21
|
"sourceSpec": "./src/vat-uploads.js"
|
|
17
22
|
},
|
|
18
23
|
"bootstrap": {
|
|
19
|
-
"sourceSpec": "@agoric/vats/src/core/boot.js"
|
|
24
|
+
"sourceSpec": "@agoric/vats/src/core/boot-solo.js"
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
27
|
}
|
package/src/add-chain.js
CHANGED
|
@@ -5,14 +5,14 @@ import djson from 'deterministic-json';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import fs from 'fs';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { Fail } from '@agoric/assert';
|
|
9
9
|
import setGCIIngress from './set-gci-ingress.js';
|
|
10
10
|
|
|
11
11
|
const DEFAULT_CHAIN_CONFIG = 'https://testnet.agoric.com/network-config';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @param {string} basedir
|
|
15
|
-
* @param {string
|
|
15
|
+
* @param {string} [chainConfig]
|
|
16
16
|
* @param {boolean} [force=false]
|
|
17
17
|
*/
|
|
18
18
|
async function addChain(basedir, chainConfig, force = false) {
|
|
@@ -60,8 +60,7 @@ async function addChain(basedir, chainConfig, force = false) {
|
|
|
60
60
|
|
|
61
61
|
netconf.gci = gci;
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
assert(netconf.gci, X`${url.href} does not contain a "gci" entry`);
|
|
63
|
+
netconf.gci || Fail`${url.href} does not contain a "gci" entry`;
|
|
65
64
|
|
|
66
65
|
const connFile = path.join(basedir, 'connections.json');
|
|
67
66
|
const conns = JSON.parse(fs.readFileSync(connFile));
|
package/src/captp.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import { E, makeCapTP } from '@endo/captp';
|
|
2
3
|
import { Far } from '@endo/marshal';
|
|
3
4
|
|
|
4
|
-
export const getCapTPHandler = (
|
|
5
|
-
|
|
6
|
-
getLocalBootstrap,
|
|
7
|
-
fallback = undefined,
|
|
8
|
-
) => {
|
|
9
|
-
let lastEpoch;
|
|
5
|
+
export const getCapTPHandler = (send, getLocalBootstrap, fallback) => {
|
|
6
|
+
let lastEpoch = 0;
|
|
10
7
|
const chans = new Map();
|
|
11
8
|
const doFallback = async (method, ...args) => {
|
|
12
9
|
if (!fallback) {
|
|
13
|
-
return
|
|
10
|
+
return false;
|
|
14
11
|
}
|
|
15
12
|
return E(fallback)[method](...args);
|
|
16
13
|
};
|
|
@@ -77,7 +74,7 @@ export const getCapTPHandler = (
|
|
|
77
74
|
}
|
|
78
75
|
const done = await doFallback('onMessage', obj, meta);
|
|
79
76
|
if (!done) {
|
|
80
|
-
console.error(`Could not find handler ${obj.type}`, meta);
|
|
77
|
+
console.error(`Could not find handler ${obj.type}`, obj, meta);
|
|
81
78
|
}
|
|
82
79
|
return done;
|
|
83
80
|
},
|
package/src/chain-cosmos-sdk.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* global setTimeout Buffer */
|
|
1
|
+
/* global clearTimeout setTimeout Buffer */
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import url from 'url';
|
|
@@ -11,36 +11,33 @@ import anylogger from 'anylogger';
|
|
|
11
11
|
import { makeNotifierKit } from '@agoric/notifier';
|
|
12
12
|
import { makePromiseKit } from '@endo/promise-kit';
|
|
13
13
|
|
|
14
|
-
import { assert,
|
|
14
|
+
import { assert, Fail } from '@agoric/assert';
|
|
15
15
|
import {
|
|
16
16
|
DEFAULT_BATCH_TIMEOUT_MS,
|
|
17
17
|
makeBatchedDeliver,
|
|
18
|
-
} from '@agoric/
|
|
18
|
+
} from '@agoric/internal/src/batched-deliver.js';
|
|
19
|
+
import { forever, whileTrue } from '@agoric/internal';
|
|
19
20
|
|
|
20
21
|
const console = anylogger('chain-cosmos-sdk');
|
|
21
22
|
|
|
22
|
-
// the `agd` tool in our repo is built
|
|
23
|
-
//
|
|
24
|
-
//
|
|
23
|
+
// the `agd` tool in our repo is built on demand. It lives in the build tree
|
|
24
|
+
// along with `bin/ag-solo`, in case there are multiple checkouts of
|
|
25
|
+
// `agoric-sdk`.
|
|
25
26
|
export const HELPER = url.fileURLToPath(
|
|
26
|
-
new URL('../../../
|
|
27
|
+
new URL('../../../bin/agd', import.meta.url),
|
|
27
28
|
);
|
|
28
29
|
|
|
29
|
-
const FAUCET_ADDRESS =
|
|
30
|
-
'the appropriate faucet channel on Discord (https://agoric.com/discord)';
|
|
31
|
-
|
|
32
30
|
// Transaction simulation should be an accurate measure of gas.
|
|
33
31
|
const GAS_ADJUSTMENT = '1.2';
|
|
34
32
|
|
|
35
33
|
const adviseEgress = egressAddr =>
|
|
36
34
|
`\
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
to ${FAUCET_ADDRESS}`;
|
|
36
|
+
Visit https://devnet.faucet.agoric.net/
|
|
37
|
+
enter address: ${egressAddr}
|
|
38
|
+
choose client, ag-solo
|
|
39
|
+
and then Submit.
|
|
40
|
+
`;
|
|
44
41
|
|
|
45
42
|
// Retry if our latest message failed.
|
|
46
43
|
const INITIAL_SEND_RETRY_DELAY_MS = 1_000;
|
|
@@ -176,7 +173,7 @@ export async function connectToChain(
|
|
|
176
173
|
async function retryRpcHref(tryOnce) {
|
|
177
174
|
let rpcHrefIndex = lastGoodRpcHrefIndex;
|
|
178
175
|
// eslint-disable-next-line no-constant-condition
|
|
179
|
-
|
|
176
|
+
for await (const _ of forever) {
|
|
180
177
|
const thisRpcHref = rpcHrefs[rpcHrefIndex];
|
|
181
178
|
|
|
182
179
|
// tryOnce will either throw if cancelled (which rejects this promise),
|
|
@@ -193,6 +190,7 @@ export async function connectToChain(
|
|
|
193
190
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
194
191
|
rpcHrefIndex = (rpcHrefIndex + 1) % rpcHrefs.length;
|
|
195
192
|
}
|
|
193
|
+
throw Error(`Unreachable, but the tools don't know that`);
|
|
196
194
|
}
|
|
197
195
|
|
|
198
196
|
let goodRpcHref = rpcHrefs[0];
|
|
@@ -612,7 +610,7 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
|
|
|
612
610
|
|
|
613
611
|
const messages = messagePool;
|
|
614
612
|
|
|
615
|
-
|
|
613
|
+
const tryBody = async () => {
|
|
616
614
|
totalDeliveries += 1;
|
|
617
615
|
console.log(
|
|
618
616
|
`delivering to chain (trips=${totalDeliveries})`,
|
|
@@ -661,7 +659,7 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
|
|
|
661
659
|
|
|
662
660
|
// We just try a single delivery per block.
|
|
663
661
|
let retry = true;
|
|
664
|
-
|
|
662
|
+
for await (const _ of whileTrue(() => retry)) {
|
|
665
663
|
retry = false;
|
|
666
664
|
// eslint-disable-next-line no-await-in-loop
|
|
667
665
|
const { stderr, stdout } = await runHelper([
|
|
@@ -690,11 +688,8 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
|
|
|
690
688
|
console.debug(`helper said: ${stdout}`);
|
|
691
689
|
const out = JSON.parse(stdout);
|
|
692
690
|
|
|
693
|
-
|
|
694
|
-
out.
|
|
695
|
-
0,
|
|
696
|
-
X`Unexpected output: ${out.raw_log || stdout.trimRight()}`,
|
|
697
|
-
);
|
|
691
|
+
out.code === 0 ||
|
|
692
|
+
Fail`Unexpected output: ${out.raw_log || stdout.trimRight()}`;
|
|
698
693
|
|
|
699
694
|
// Wait for the transaction to be included in a block.
|
|
700
695
|
const txHash = out.txhash;
|
|
@@ -704,7 +699,7 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
|
|
|
704
699
|
if (txResult.code) {
|
|
705
700
|
// eslint-disable-next-line no-use-before-define
|
|
706
701
|
failedSend(
|
|
707
|
-
assert.error(
|
|
702
|
+
assert.error(`Error in tx processing: ${txResult.log}`),
|
|
708
703
|
);
|
|
709
704
|
}
|
|
710
705
|
});
|
|
@@ -715,11 +710,9 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
|
|
|
715
710
|
sequenceNumber += 1n;
|
|
716
711
|
}
|
|
717
712
|
}
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
}
|
|
722
|
-
}
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
await tryBody().finally(() => tmpInfo && fs.promises.unlink(tmpInfo.path));
|
|
723
716
|
};
|
|
724
717
|
|
|
725
718
|
/**
|
|
@@ -728,13 +721,13 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
|
|
|
728
721
|
*
|
|
729
722
|
* It then delivers the mailbox to inbound. There are no optimisations.
|
|
730
723
|
*
|
|
731
|
-
* @param {
|
|
724
|
+
* @param {bigint} [lastMailboxUpdate]
|
|
732
725
|
*/
|
|
733
726
|
const recurseEachMailboxUpdate = async (lastMailboxUpdate = undefined) => {
|
|
734
727
|
const { updateCount, value: mailbox } = await mbNotifier.getUpdateSince(
|
|
735
728
|
lastMailboxUpdate,
|
|
736
729
|
);
|
|
737
|
-
|
|
730
|
+
updateCount || Fail`${GCI} unexpectedly finished!`;
|
|
738
731
|
if (mailbox) {
|
|
739
732
|
const { outbox, ack } = mailbox;
|
|
740
733
|
// console.info('have mailbox', mailbox);
|
|
@@ -780,11 +773,11 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
|
|
|
780
773
|
};
|
|
781
774
|
|
|
782
775
|
// This function ensures we only have one outgoing send operation at a time.
|
|
783
|
-
/** @type {(lastSendUpdate?:
|
|
776
|
+
/** @type {(lastSendUpdate?: bigint) => Promise<void>} */
|
|
784
777
|
const recurseEachSend = async (lastSendUpdate = undefined) => {
|
|
785
778
|
// See when there is another requested send since our last time.
|
|
786
779
|
const { updateCount } = await sendNotifier.getUpdateSince(lastSendUpdate);
|
|
787
|
-
|
|
780
|
+
updateCount || Fail`Sending unexpectedly finished!`;
|
|
788
781
|
|
|
789
782
|
await sendFromMessagePool().then(successfulSend, failedSend);
|
|
790
783
|
recurseEachSend(updateCount);
|
|
@@ -813,5 +806,9 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
|
|
|
813
806
|
|
|
814
807
|
// Now that we've started consuming blocks, tell our caller how to deliver
|
|
815
808
|
// messages.
|
|
816
|
-
return makeBatchedDeliver(
|
|
809
|
+
return makeBatchedDeliver(
|
|
810
|
+
deliver,
|
|
811
|
+
{ clearTimeout, setTimeout },
|
|
812
|
+
Math.min(DEFAULT_BATCH_TIMEOUT_MS, 2000),
|
|
813
|
+
);
|
|
817
814
|
}
|
package/src/entrypoint.js
CHANGED
package/src/outbound.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* global process */
|
|
2
2
|
import anylogger from 'anylogger';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { Fail } from '@agoric/assert';
|
|
5
5
|
|
|
6
6
|
// Limit the debug log length.
|
|
7
7
|
const SOLO_MAX_DEBUG_LENGTH =
|
|
@@ -28,7 +28,7 @@ export function deliver(mbs) {
|
|
|
28
28
|
for (const target of Object.getOwnPropertyNames(data)) {
|
|
29
29
|
if (!knownTargets.has(target)) {
|
|
30
30
|
log.error(`eek, no delivery method for target`, target);
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
continue;
|
|
33
33
|
}
|
|
34
34
|
const t = knownTargets.get(target);
|
|
@@ -62,7 +62,7 @@ export function deliver(mbs) {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
export function addDeliveryTarget(target, deliverator) {
|
|
65
|
-
|
|
65
|
+
!knownTargets.has(target) || Fail`target ${target} already added`;
|
|
66
66
|
/** @type {TargetRecord} */
|
|
67
67
|
const targetRecord = { deliverator, highestSent: 0, highestAck: 0 };
|
|
68
68
|
knownTargets.set(target, targetRecord);
|
package/src/pipe-entrypoint.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* global process */
|
|
2
2
|
// @ts-check
|
|
3
3
|
import '@endo/init/pre-bundle-source.js';
|
|
4
|
-
import 'lmdb';
|
|
5
4
|
import '@endo/init';
|
|
6
5
|
|
|
7
6
|
import { parse, stringify } from '@endo/marshal';
|
|
@@ -9,7 +8,7 @@ import { makePromiseKit } from '@endo/promise-kit';
|
|
|
9
8
|
|
|
10
9
|
import '@agoric/cosmic-swingset/src/anylogger-agoric.js';
|
|
11
10
|
import { connectToFakeChain } from '@agoric/cosmic-swingset/src/sim-chain.js';
|
|
12
|
-
import { makeShutdown } from '@agoric/
|
|
11
|
+
import { makeShutdown } from '@agoric/internal/src/node/shutdown.js';
|
|
13
12
|
|
|
14
13
|
const { registerShutdown } = makeShutdown(false);
|
|
15
14
|
registerShutdown(() => process.exit());
|
package/src/pipe.js
CHANGED
|
@@ -5,7 +5,7 @@ import path from 'path';
|
|
|
5
5
|
import { makePromiseKit } from '@endo/promise-kit';
|
|
6
6
|
import { parse, stringify } from '@endo/marshal';
|
|
7
7
|
|
|
8
|
-
import { makeShutdown } from '@agoric/
|
|
8
|
+
import { makeShutdown } from '@agoric/internal/src/node/shutdown.js';
|
|
9
9
|
|
|
10
10
|
const filename = new URL(import.meta.url).pathname;
|
|
11
11
|
const dirname = path.dirname(filename);
|
package/src/reset-state.js
CHANGED
|
@@ -10,7 +10,7 @@ export default async function resetState(basedir) {
|
|
|
10
10
|
);
|
|
11
11
|
fs.writeFileSync(mailboxStateFile, `{}\n`);
|
|
12
12
|
const kernelStateDBDir = path.join(basedir, 'swingset-kernel-state');
|
|
13
|
-
const { commit, close } = initSwingStore(kernelStateDBDir);
|
|
13
|
+
const { commit, close } = initSwingStore(kernelStateDBDir).hostStorage;
|
|
14
14
|
await commit();
|
|
15
15
|
await close();
|
|
16
16
|
}
|
package/src/start.js
CHANGED
|
@@ -16,8 +16,8 @@ import anylogger from 'anylogger';
|
|
|
16
16
|
// import connect from 'lotion-connect';
|
|
17
17
|
// import djson from 'deterministic-json';
|
|
18
18
|
|
|
19
|
-
import { assert,
|
|
20
|
-
import { makeSlogSender } from '@agoric/telemetry';
|
|
19
|
+
import { assert, Fail } from '@agoric/assert';
|
|
20
|
+
import { makeSlogSender, tryFlushSlogSender } from '@agoric/telemetry';
|
|
21
21
|
import {
|
|
22
22
|
loadSwingsetConfigFile,
|
|
23
23
|
buildCommand,
|
|
@@ -30,8 +30,8 @@ import {
|
|
|
30
30
|
buildTimer,
|
|
31
31
|
} from '@agoric/swingset-vat';
|
|
32
32
|
import { openSwingStore } from '@agoric/swing-store';
|
|
33
|
-
import { makeWithQueue } from '@agoric/
|
|
34
|
-
import { makeShutdown } from '@agoric/
|
|
33
|
+
import { makeWithQueue } from '@agoric/internal/src/queue.js';
|
|
34
|
+
import { makeShutdown } from '@agoric/internal/src/node/shutdown.js';
|
|
35
35
|
import {
|
|
36
36
|
makeDefaultMeterProvider,
|
|
37
37
|
getTelemetryProviders,
|
|
@@ -129,7 +129,7 @@ const buildSwingset = async (
|
|
|
129
129
|
// Ensure they can't traverse out of the plugins prefix.
|
|
130
130
|
const pluginFile = path.resolve(pluginsPrefix, mod);
|
|
131
131
|
pluginFile.startsWith(pluginsPrefix) ||
|
|
132
|
-
|
|
132
|
+
Fail`Cannot load ${pluginFile} plugin; outside of ${pluginDir}`;
|
|
133
133
|
|
|
134
134
|
// TODO: Detect the module type and use the appropriate loader, just like
|
|
135
135
|
// `agoric deploy`.
|
|
@@ -165,7 +165,7 @@ const buildSwingset = async (
|
|
|
165
165
|
|
|
166
166
|
const soloEnv = Object.fromEntries(
|
|
167
167
|
Object.entries(process.env)
|
|
168
|
-
.filter(([k]) => k.match(/^SOLO_/)) // narrow to SOLO_ prefixes.
|
|
168
|
+
.filter(([k]) => k.match(/^SOLO_/)) // narrow to SOLO_ prefixes. e.g. SOLO_SLOGFILE
|
|
169
169
|
.map(([k, v]) => [k.replace(/^SOLO_/, ''), v]), // Replace SOLO_ controls with chain version.
|
|
170
170
|
);
|
|
171
171
|
const env = {
|
|
@@ -179,8 +179,7 @@ const buildSwingset = async (
|
|
|
179
179
|
serviceName: TELEMETRY_SERVICE_NAME,
|
|
180
180
|
});
|
|
181
181
|
|
|
182
|
-
const {
|
|
183
|
-
const mapSize = (LMDB_MAP_SIZE && parseInt(LMDB_MAP_SIZE, 10)) || undefined;
|
|
182
|
+
const { SWING_STORE_TRACE, XSNAP_KEEP_SNAPSHOTS } = env;
|
|
184
183
|
|
|
185
184
|
const defaultTraceFile = path.resolve(kernelStateDBDir, 'store-trace.log');
|
|
186
185
|
let swingStoreTraceFile;
|
|
@@ -201,15 +200,10 @@ const buildSwingset = async (
|
|
|
201
200
|
const keepSnapshots =
|
|
202
201
|
XSNAP_KEEP_SNAPSHOTS === '1' || XSNAP_KEEP_SNAPSHOTS === 'true';
|
|
203
202
|
|
|
204
|
-
const {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
);
|
|
208
|
-
const hostStorage = {
|
|
209
|
-
kvStore,
|
|
210
|
-
streamStore,
|
|
211
|
-
snapStore,
|
|
212
|
-
};
|
|
203
|
+
const { kernelStorage, hostStorage } = openSwingStore(kernelStateDBDir, {
|
|
204
|
+
traceFile: swingStoreTraceFile,
|
|
205
|
+
keepSnapshots,
|
|
206
|
+
});
|
|
213
207
|
|
|
214
208
|
// Not to be confused with the gas model, this meter is for OpenTelemetry.
|
|
215
209
|
const metricMeter = metricsProvider.getMeter('ag-solo');
|
|
@@ -217,11 +211,11 @@ const buildSwingset = async (
|
|
|
217
211
|
metricMeter,
|
|
218
212
|
});
|
|
219
213
|
|
|
220
|
-
if (!swingsetIsInitialized(
|
|
214
|
+
if (!swingsetIsInitialized(kernelStorage)) {
|
|
221
215
|
if (defaultManagerType && !config.defaultManagerType) {
|
|
222
216
|
config.defaultManagerType = defaultManagerType;
|
|
223
217
|
}
|
|
224
|
-
await initializeSwingset(config, argv,
|
|
218
|
+
await initializeSwingset(config, argv, kernelStorage);
|
|
225
219
|
}
|
|
226
220
|
const slogSender = await makeSlogSender({
|
|
227
221
|
stateDir: kernelStateDBDir,
|
|
@@ -229,7 +223,7 @@ const buildSwingset = async (
|
|
|
229
223
|
env,
|
|
230
224
|
});
|
|
231
225
|
const controller = await makeSwingsetController(
|
|
232
|
-
|
|
226
|
+
kernelStorage,
|
|
233
227
|
deviceEndowments,
|
|
234
228
|
{ env, slogCallbacks, slogSender },
|
|
235
229
|
);
|
|
@@ -243,7 +237,7 @@ const buildSwingset = async (
|
|
|
243
237
|
async function saveState() {
|
|
244
238
|
const ms = JSON.stringify(mbs.exportToData());
|
|
245
239
|
await atomicReplaceFile(mailboxStateFile, ms);
|
|
246
|
-
await commit();
|
|
240
|
+
await hostStorage.commit();
|
|
247
241
|
}
|
|
248
242
|
|
|
249
243
|
function deliverOutbound() {
|
|
@@ -254,17 +248,19 @@ const buildSwingset = async (
|
|
|
254
248
|
|
|
255
249
|
async function processKernel() {
|
|
256
250
|
await crankScheduler(policy);
|
|
257
|
-
if (swingSetRunning) {
|
|
258
|
-
|
|
259
|
-
deliverOutbound();
|
|
251
|
+
if (!swingSetRunning) {
|
|
252
|
+
return;
|
|
260
253
|
}
|
|
254
|
+
await saveState();
|
|
255
|
+
deliverOutbound();
|
|
256
|
+
await tryFlushSlogSender(slogSender, { env, log: console.warn });
|
|
261
257
|
}
|
|
262
258
|
|
|
263
259
|
// Use the input queue to make sure it doesn't overlap with
|
|
264
260
|
// other inbound messages.
|
|
265
261
|
const queuedDeliverInboundToMbx = withInputQueue(
|
|
266
262
|
async function deliverInboundToMbx(sender, messages, ack) {
|
|
267
|
-
|
|
263
|
+
Array.isArray(messages) || Fail`inbound given non-Array: ${messages}`;
|
|
268
264
|
// console.debug(`deliverInboundToMbx`, messages, ack);
|
|
269
265
|
if (mb.deliverInbound(sender, messages, ack)) {
|
|
270
266
|
await processKernel();
|
|
@@ -365,9 +361,11 @@ const deployWallet = async ({ agWallet, deploys, hostport }) => {
|
|
|
365
361
|
// This part only runs if there were wallet deploys to do.
|
|
366
362
|
const resolvedDeploys = deploys.map(dep => path.resolve(agWallet, dep));
|
|
367
363
|
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
364
|
+
const resolvedUrl = await importMetaResolve(
|
|
365
|
+
'agoric/src/entrypoint.js',
|
|
366
|
+
import.meta.url,
|
|
367
|
+
);
|
|
368
|
+
const agoricCli = new URL(resolvedUrl).pathname;
|
|
371
369
|
|
|
372
370
|
// Use the same verbosity as our caller did for us.
|
|
373
371
|
let verbosity;
|
|
@@ -414,10 +412,8 @@ const start = async (basedir, argv) => {
|
|
|
414
412
|
const rawConnections = JSON.parse(
|
|
415
413
|
fs.readFileSync(rawConnectionsPath, 'utf8'),
|
|
416
414
|
);
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
`Invalid connections.json: must be a JSON array, at ${rawConnectionsPath}`,
|
|
420
|
-
);
|
|
415
|
+
Array.isArray(rawConnections) ||
|
|
416
|
+
Fail`Invalid connections.json: must be a JSON array, at ${rawConnectionsPath}`;
|
|
421
417
|
const homeDirectory = process.cwd();
|
|
422
418
|
const connections = rawConnections.map(connection => {
|
|
423
419
|
if (['chain-cosmos-sdk', 'fake-chain'].includes(connection.type)) {
|
|
@@ -478,10 +474,12 @@ const start = async (basedir, argv) => {
|
|
|
478
474
|
// Remove wallet traces.
|
|
479
475
|
await unlink('html/wallet').catch(_ => {});
|
|
480
476
|
|
|
477
|
+
const packageUrl = await importMetaResolve(
|
|
478
|
+
`${wallet}/package.json`,
|
|
479
|
+
import.meta.url,
|
|
480
|
+
);
|
|
481
481
|
// Find the wallet.
|
|
482
|
-
const pjs = new URL(
|
|
483
|
-
await importMetaResolve(`${wallet}/package.json`, import.meta.url),
|
|
484
|
-
).pathname;
|
|
482
|
+
const pjs = new URL(packageUrl).pathname;
|
|
485
483
|
const { 'agoric-wallet': { htmlBasedir = 'ui/build', deploy = [] } = {} } =
|
|
486
484
|
JSON.parse(fs.readFileSync(pjs, 'utf-8'));
|
|
487
485
|
|
|
@@ -520,7 +518,7 @@ const start = async (basedir, argv) => {
|
|
|
520
518
|
}
|
|
521
519
|
case 'http': {
|
|
522
520
|
log(`adding HTTP/WS listener on ${c.host}:${c.port}`);
|
|
523
|
-
|
|
521
|
+
!broadcastJSON || Fail`duplicate type=http in connections.json`;
|
|
524
522
|
hostport = `${c.host}:${c.port}`;
|
|
525
523
|
broadcastJSON = await makeHTTPListener(
|
|
526
524
|
basedir,
|
|
@@ -534,7 +532,7 @@ const start = async (basedir, argv) => {
|
|
|
534
532
|
break;
|
|
535
533
|
}
|
|
536
534
|
default: {
|
|
537
|
-
|
|
535
|
+
Fail`unknown connection type in ${c}`;
|
|
538
536
|
}
|
|
539
537
|
}
|
|
540
538
|
}),
|
package/src/vat-http.js
CHANGED
|
@@ -2,7 +2,7 @@ import { makeNotifierKit } from '@agoric/notifier';
|
|
|
2
2
|
import { makeCache } from '@agoric/cache';
|
|
3
3
|
import { E } from '@endo/eventual-send';
|
|
4
4
|
import { Far } from '@endo/marshal';
|
|
5
|
-
import {
|
|
5
|
+
import { Fail } from '@agoric/assert';
|
|
6
6
|
import { getReplHandler } from '@agoric/vats/src/repl.js';
|
|
7
7
|
import { makePromiseKit } from '@endo/promise-kit';
|
|
8
8
|
import { getCapTPHandler } from './captp.js';
|
|
@@ -41,7 +41,7 @@ export function buildRootObject(vatPowers) {
|
|
|
41
41
|
if (remaining.length === 0) {
|
|
42
42
|
return firstValue;
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
firstValue || Fail`${first} not found in home`;
|
|
45
45
|
return E(firstValue).lookup(...remaining);
|
|
46
46
|
};
|
|
47
47
|
harden(lookup);
|
|
@@ -102,14 +102,6 @@ export function buildRootObject(vatPowers) {
|
|
|
102
102
|
urlToHandler.set(url, commandHandler);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
const { promise: walletP, resolve: resolveWallet } = makePromiseKit();
|
|
106
|
-
const { promise: attMakerP, resolve: resolveAttMaker } = makePromiseKit();
|
|
107
|
-
Promise.all([walletP, attMakerP]).then(async ([wallet, attMaker]) => {
|
|
108
|
-
const walletAdmin = await E(wallet).getAdminFacet();
|
|
109
|
-
// console.debug('introduce', { wallet, walletAdmin, attMaker });
|
|
110
|
-
E(walletAdmin).resolveAttMaker(attMaker);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
105
|
return Far('root', {
|
|
114
106
|
setCommandDevice(d) {
|
|
115
107
|
commandDevice = d;
|
|
@@ -146,8 +138,6 @@ export function buildRootObject(vatPowers) {
|
|
|
146
138
|
replObjects.local.wallet = wallet;
|
|
147
139
|
replObjects.home.wallet = wallet;
|
|
148
140
|
resolveCacheCooordinator(E(E(wallet).getBridge()).getCacheCoordinator());
|
|
149
|
-
|
|
150
|
-
resolveWallet(wallet);
|
|
151
141
|
},
|
|
152
142
|
|
|
153
143
|
/**
|
|
@@ -178,10 +168,6 @@ export function buildRootObject(vatPowers) {
|
|
|
178
168
|
...rest
|
|
179
169
|
} = decentralObjects;
|
|
180
170
|
decentralObjects = rest;
|
|
181
|
-
|
|
182
|
-
if (decentralObjects.attMaker) {
|
|
183
|
-
resolveAttMaker(decentralObjects.attMaker);
|
|
184
|
-
}
|
|
185
171
|
}
|
|
186
172
|
|
|
187
173
|
// TODO: Maybe remove sometime; home object is deprecated.
|
|
@@ -242,7 +228,7 @@ export function buildRootObject(vatPowers) {
|
|
|
242
228
|
|
|
243
229
|
if (dispatcher === 'onMessage') {
|
|
244
230
|
sendResponse(count, false, { type: 'doesNotUnderstand', obj });
|
|
245
|
-
|
|
231
|
+
Fail`No handler for ${url} ${type}`;
|
|
246
232
|
}
|
|
247
233
|
sendResponse(count, false, true);
|
|
248
234
|
} catch (rej) {
|
package/src/vat-uploads.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Far } from '@endo/marshal';
|
|
2
|
-
import makeScratchPad from '
|
|
2
|
+
import makeScratchPad from '@agoric/internal/src/scratch.js';
|
|
3
3
|
|
|
4
4
|
// This vat contains the private upload scratch pad.
|
|
5
5
|
|
|
6
|
-
export function buildRootObject(
|
|
6
|
+
export function buildRootObject() {
|
|
7
7
|
const uploads = makeScratchPad();
|
|
8
8
|
|
|
9
9
|
function getUploads() {
|
package/src/web.js
CHANGED
|
@@ -210,7 +210,8 @@ export async function makeHTTPListener(
|
|
|
210
210
|
|
|
211
211
|
// accept POST messages as commands.
|
|
212
212
|
app.post('*', async (req, res) => {
|
|
213
|
-
|
|
213
|
+
const valid = await validateAccessToken(req);
|
|
214
|
+
if (!valid) {
|
|
214
215
|
res.json({ ok: false, rej: 'Unauthorized' });
|
|
215
216
|
return;
|
|
216
217
|
}
|
|
@@ -225,7 +226,8 @@ export async function makeHTTPListener(
|
|
|
225
226
|
});
|
|
226
227
|
|
|
227
228
|
app.get('/connections', async (req, res) => {
|
|
228
|
-
|
|
229
|
+
const valid = await validateAccessToken(req);
|
|
230
|
+
if (!valid) {
|
|
229
231
|
res.json({ ok: false, rej: 'Unauthorized' });
|
|
230
232
|
return;
|
|
231
233
|
}
|
|
@@ -237,7 +239,8 @@ export async function makeHTTPListener(
|
|
|
237
239
|
});
|
|
238
240
|
|
|
239
241
|
app.post('/publish-bundle', async (req, res) => {
|
|
240
|
-
|
|
242
|
+
const valid = await validateAccessToken(req);
|
|
243
|
+
if (!valid) {
|
|
241
244
|
res.json({ ok: false, rej: 'Unauthorized' });
|
|
242
245
|
return;
|
|
243
246
|
}
|
|
@@ -256,7 +259,8 @@ export async function makeHTTPListener(
|
|
|
256
259
|
// GETs (which should return index.html) and WebSocket requests.
|
|
257
260
|
const wss = new WebSocket.Server({ noServer: true });
|
|
258
261
|
server.on('upgrade', async (req, socket, head) => {
|
|
259
|
-
|
|
262
|
+
const valid = await validateAccessToken(req);
|
|
263
|
+
if (!valid) {
|
|
260
264
|
socket.destroy();
|
|
261
265
|
return;
|
|
262
266
|
}
|
|
@@ -352,6 +356,9 @@ export async function makeHTTPListener(
|
|
|
352
356
|
try {
|
|
353
357
|
obj = JSON.parse(message);
|
|
354
358
|
const res = await inboundCommand(obj, meta, id);
|
|
359
|
+
if (typeof res === 'boolean') {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
355
362
|
|
|
356
363
|
// eslint-disable-next-line no-use-before-define
|
|
357
364
|
sendJSON({ ...res, meta });
|
|
@@ -367,9 +374,7 @@ export async function makeHTTPListener(
|
|
|
367
374
|
wss.on('connection', newChannel);
|
|
368
375
|
|
|
369
376
|
function sendJSON(rawObj) {
|
|
370
|
-
const { meta: { channelID } = {} } = rawObj;
|
|
371
|
-
const obj = { ...rawObj };
|
|
372
|
-
delete obj.meta;
|
|
377
|
+
const { meta: { channelID } = {}, ...obj } = rawObj;
|
|
373
378
|
|
|
374
379
|
// Point-to-point.
|
|
375
380
|
const c = channels.get(channelID);
|
package/test/captp-fixture.js
CHANGED
|
@@ -44,7 +44,7 @@ export async function makeFixture(PORT, noisy = false) {
|
|
|
44
44
|
/** @type {() => void} */
|
|
45
45
|
let abortCapTP;
|
|
46
46
|
ws = new WebSocket(
|
|
47
|
-
`ws://
|
|
47
|
+
`ws://127.0.0.1:${PORT}/private/captp?accessToken=${accessToken}`,
|
|
48
48
|
{
|
|
49
49
|
origin: `http://localhost:${PORT}`,
|
|
50
50
|
},
|
|
@@ -107,7 +107,7 @@ export async function makeFixture(PORT, noisy = false) {
|
|
|
107
107
|
console.log(buf);
|
|
108
108
|
}
|
|
109
109
|
// We only reject if the child exits before CapTP is established.
|
|
110
|
-
reject(
|
|
110
|
+
reject(Error(`CapTP fixture exited with ${code}`));
|
|
111
111
|
});
|
|
112
112
|
tryConnect(resolve, reject);
|
|
113
113
|
});
|
package/test/test-home.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { test } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js';
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import bundleSourceAmbient from '@endo/bundle-source';
|
|
6
6
|
import { AmountMath } from '@agoric/ertp';
|
|
7
|
+
import { TimeMath } from '@agoric/time';
|
|
7
8
|
import { Stable } from '@agoric/vats/src/tokens.js';
|
|
8
9
|
import { Far } from '@endo/marshal';
|
|
9
10
|
import { resolve as importMetaResolve } from 'import-meta-resolve';
|
|
@@ -12,20 +13,29 @@ import { makeFixture, E } from './captp-fixture.js';
|
|
|
12
13
|
|
|
13
14
|
const SOLO_PORT = 7999;
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
let home;
|
|
17
|
-
let teardown;
|
|
16
|
+
//#region setup (ambient authority is confined to this region)
|
|
18
17
|
test.before('setup', async t => {
|
|
18
|
+
const loadBundle = async specifier => {
|
|
19
|
+
const contractUrl = await importMetaResolve(specifier, import.meta.url);
|
|
20
|
+
const contractRoot = new URL(contractUrl).pathname;
|
|
21
|
+
t.log({ contractRoot });
|
|
22
|
+
const bundle = await bundleSourceAmbient(contractRoot);
|
|
23
|
+
return bundle;
|
|
24
|
+
};
|
|
19
25
|
const { homeP, kill } = await makeFixture(SOLO_PORT, process.env.NOISY);
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
const home = await homeP;
|
|
27
|
+
|
|
28
|
+
t.context = { home, teardown: kill, loadBundle };
|
|
29
|
+
|
|
22
30
|
t.truthy('ready');
|
|
23
31
|
});
|
|
32
|
+
//#endregion
|
|
24
33
|
|
|
25
34
|
// Now come the tests that use `home`...
|
|
26
35
|
// =========================================
|
|
27
36
|
|
|
28
37
|
test.serial('home.board', async t => {
|
|
38
|
+
const { home } = t.context;
|
|
29
39
|
const { board } = E.get(home);
|
|
30
40
|
await t.throwsAsync(
|
|
31
41
|
() => E(board).getValue('board0120'),
|
|
@@ -50,6 +60,7 @@ test.serial('home.board', async t => {
|
|
|
50
60
|
});
|
|
51
61
|
|
|
52
62
|
test.serial('home.wallet - transfer funds to the feePurse', async t => {
|
|
63
|
+
const { home } = t.context;
|
|
53
64
|
const { wallet, faucet } = E.get(home);
|
|
54
65
|
const feePurse = E(faucet).getFeePurse();
|
|
55
66
|
const feeBrand = await E(feePurse).getAllegedBrand();
|
|
@@ -62,16 +73,13 @@ test.serial('home.wallet - transfer funds to the feePurse', async t => {
|
|
|
62
73
|
});
|
|
63
74
|
|
|
64
75
|
test.serial('home.wallet - receive zoe invite', async t => {
|
|
76
|
+
const { home, loadBundle } = t.context;
|
|
65
77
|
const { wallet, zoe, board } = E.get(home);
|
|
66
78
|
|
|
67
79
|
// Setup contract in order to get an invite to use in tests
|
|
68
|
-
const
|
|
80
|
+
const bundle = await loadBundle(
|
|
69
81
|
'@agoric/zoe/src/contracts/automaticRefund.js',
|
|
70
|
-
import.meta.url,
|
|
71
82
|
);
|
|
72
|
-
const contractRoot = new URL(contractUrl).pathname;
|
|
73
|
-
t.log({ contractRoot });
|
|
74
|
-
const bundle = await bundleSource(contractRoot);
|
|
75
83
|
const installationHandle = await E(zoe).install(bundle);
|
|
76
84
|
const { creatorInvitation: invite } = await E(zoe).startInstance(
|
|
77
85
|
installationHandle,
|
|
@@ -113,6 +121,7 @@ test.serial('home.wallet - receive zoe invite', async t => {
|
|
|
113
121
|
});
|
|
114
122
|
|
|
115
123
|
test.serial('home.wallet - central issuer setup', async t => {
|
|
124
|
+
const { home } = t.context;
|
|
116
125
|
const { wallet } = E.get(home);
|
|
117
126
|
|
|
118
127
|
// Check that the wallet knows about the central issuer.
|
|
@@ -127,6 +136,7 @@ test.serial('home.wallet - central issuer setup', async t => {
|
|
|
127
136
|
});
|
|
128
137
|
|
|
129
138
|
test.serial('home.localTimerService makeNotifier', async t => {
|
|
139
|
+
const { home } = t.context;
|
|
130
140
|
const { localTimerService } = E.get(home);
|
|
131
141
|
const notifier = E(localTimerService).makeNotifier(1n, 1n);
|
|
132
142
|
const update1 = await E(notifier).getUpdateSince();
|
|
@@ -137,7 +147,7 @@ test.serial('home.localTimerService makeNotifier', async t => {
|
|
|
137
147
|
|
|
138
148
|
// Tests gets an actual localTimerService, which returns actual times. We
|
|
139
149
|
// can't verify the actual time, so we compare to make sure it's increasing.
|
|
140
|
-
t.truthy(update2.value
|
|
150
|
+
t.truthy(TimeMath.compareAbs(update2.value, update1.value) > 0);
|
|
141
151
|
});
|
|
142
152
|
|
|
143
153
|
function makeHandler() {
|
|
@@ -158,6 +168,7 @@ function makeHandler() {
|
|
|
158
168
|
}
|
|
159
169
|
|
|
160
170
|
test.serial('home.localTimerService makeRepeater', async t => {
|
|
171
|
+
const { home } = t.context;
|
|
161
172
|
const { localTimerService } = E.get(home);
|
|
162
173
|
const timestamp = await E(localTimerService).getCurrentTimestamp();
|
|
163
174
|
const repeater = E(localTimerService).makeRepeater(1n, 1n);
|
|
@@ -167,12 +178,13 @@ test.serial('home.localTimerService makeRepeater', async t => {
|
|
|
167
178
|
await E(notifier).getUpdateSince();
|
|
168
179
|
|
|
169
180
|
t.truthy(handler.getCalls() >= 1);
|
|
170
|
-
t.truthy(handler.getArgs()[0] >
|
|
181
|
+
t.truthy(TimeMath.compareAbs(handler.getArgs()[0], timestamp) > 0);
|
|
171
182
|
});
|
|
172
183
|
|
|
173
184
|
// =========================================
|
|
174
185
|
// This runs after all the tests.
|
|
175
186
|
test.after.always('teardown', async t => {
|
|
187
|
+
const { teardown } = t.context;
|
|
176
188
|
await teardown();
|
|
177
189
|
t.truthy('shutdown');
|
|
178
190
|
});
|
package/src/scratch.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { E } from '@endo/eventual-send';
|
|
2
|
-
import { Far } from '@endo/marshal';
|
|
3
|
-
|
|
4
|
-
export default function makeScratchPad() {
|
|
5
|
-
const map = new Map();
|
|
6
|
-
|
|
7
|
-
const keys = async () => {
|
|
8
|
-
const keyList = [...map.keys()];
|
|
9
|
-
return harden(keyList.sort());
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const scratch = Far('scratchPad', {
|
|
13
|
-
delete: async keyP => {
|
|
14
|
-
const key = await keyP;
|
|
15
|
-
map.delete(key);
|
|
16
|
-
},
|
|
17
|
-
get: async keyP => {
|
|
18
|
-
const key = await keyP;
|
|
19
|
-
return map.get(key);
|
|
20
|
-
},
|
|
21
|
-
lookup: (...path) => {
|
|
22
|
-
if (path.length === 0) {
|
|
23
|
-
return scratch;
|
|
24
|
-
}
|
|
25
|
-
const [first, ...rest] = path;
|
|
26
|
-
const firstValue = E(scratch).get(first);
|
|
27
|
-
if (rest.length === 0) {
|
|
28
|
-
return firstValue;
|
|
29
|
-
}
|
|
30
|
-
return E(firstValue).lookup(...rest);
|
|
31
|
-
},
|
|
32
|
-
// Initialize a key only if it doesn't already exist. Needed for atomicity
|
|
33
|
-
// between multiple invocations.
|
|
34
|
-
init: async (keyP, objP) => {
|
|
35
|
-
const [key, obj] = await Promise.all([keyP, objP]);
|
|
36
|
-
if (map.has(key)) {
|
|
37
|
-
throw Error(`Scratchpad already has key ${key}`);
|
|
38
|
-
}
|
|
39
|
-
map.set(key, obj);
|
|
40
|
-
return key;
|
|
41
|
-
},
|
|
42
|
-
keys,
|
|
43
|
-
// Legacy alias for `keys`.
|
|
44
|
-
list: keys,
|
|
45
|
-
set: async (keyP, objP) => {
|
|
46
|
-
const [key, obj] = await Promise.all([keyP, objP]);
|
|
47
|
-
map.set(key, obj);
|
|
48
|
-
return key;
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
return scratch;
|
|
52
|
-
}
|
|
53
|
-
/** @typedef {ReturnType<typeof makeScratchPad>} ScratchPad */
|