@agoric/swingset-liveslots 0.10.3-dev-4733782.0 → 0.10.3-dev-af3ced9.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/swingset-liveslots",
|
|
3
|
-
"version": "0.10.3-dev-
|
|
3
|
+
"version": "0.10.3-dev-af3ced9.0+af3ced9",
|
|
4
4
|
"description": "SwingSet ocap support layer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"lint:eslint": "eslint ."
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@agoric/assert": "0.6.1-dev-
|
|
21
|
-
"@agoric/internal": "0.3.3-dev-
|
|
22
|
-
"@agoric/store": "0.9.3-dev-
|
|
20
|
+
"@agoric/assert": "0.6.1-dev-af3ced9.0+af3ced9",
|
|
21
|
+
"@agoric/internal": "0.3.3-dev-af3ced9.0+af3ced9",
|
|
22
|
+
"@agoric/store": "0.9.3-dev-af3ced9.0+af3ced9",
|
|
23
23
|
"@endo/env-options": "^1.1.2",
|
|
24
24
|
"@endo/errors": "^1.2.0",
|
|
25
25
|
"@endo/eventual-send": "^1.2.0",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"@endo/promise-kit": "^1.1.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@agoric/kmarshal": "0.1.1-dev-
|
|
36
|
+
"@agoric/kmarshal": "0.1.1-dev-af3ced9.0+af3ced9",
|
|
37
37
|
"ava": "^5.3.0"
|
|
38
38
|
},
|
|
39
39
|
"files": [
|
|
@@ -69,5 +69,5 @@
|
|
|
69
69
|
"typeCoverage": {
|
|
70
70
|
"atLeast": 75.22
|
|
71
71
|
},
|
|
72
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "af3ced91861731353e10a45e4eae63450f74a0ea"
|
|
73
73
|
}
|
package/src/vatDataTypes.d.ts
CHANGED
|
@@ -73,6 +73,41 @@ export type DefineKindOptions<C> = {
|
|
|
73
73
|
finish?: (context: C) => void;
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
+
* If provided, it describes the shape of all state records of instances
|
|
77
|
+
* of this kind.
|
|
78
|
+
*/
|
|
79
|
+
stateShape?: StateShape;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* If a `receiveAmplifier` function is provided to an exo class kit definition,
|
|
83
|
+
* it will be called with an `Amplify` function. If provided to the definition
|
|
84
|
+
* of a normal exo or exo class, the definition will throw, since only
|
|
85
|
+
* exo kits can be amplified.
|
|
86
|
+
* An `Amplify` function is a function that takes a facet instance of
|
|
87
|
+
* this class kit as an argument, in which case it will return the facets
|
|
88
|
+
* record, giving access to all the facet instances of the same cohort.
|
|
89
|
+
*/
|
|
90
|
+
receiveAmplifier?: ReceivePower<Amplify<F>>;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* If a `receiveInstanceTester` function is provided, it will be called
|
|
94
|
+
* during the definition of the exo class or exo class kit with an
|
|
95
|
+
* `IsInstance` function. The first argument of `IsInstance`
|
|
96
|
+
* is the value to be tested. When it may be a facet instance of an
|
|
97
|
+
* exo class kit, the optional second argument, if provided, is
|
|
98
|
+
* a `facetName`. In that case, the function tests only if the first
|
|
99
|
+
* argument is an instance of that facet of the associated exo class kit.
|
|
100
|
+
*/
|
|
101
|
+
receiveInstanceTester?: ReceivePower<IsInstance>;
|
|
102
|
+
|
|
103
|
+
// TODO properties above are identical to those in FarClassOptions.
|
|
104
|
+
// These are the only options that should be exposed by
|
|
105
|
+
// vat-data's public virtual/durable exo APIs. This DefineKindOptions
|
|
106
|
+
// should explicitly be a subtype, where the methods below are only for
|
|
107
|
+
// internal use, i.e., below the exo level.
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* As a kind option, intended for internal use only.
|
|
76
111
|
* Meaningful to `makeScalarBigMapStore` and its siblings. These maker
|
|
77
112
|
* fuctions will make either virtual or durable stores, depending on
|
|
78
113
|
* this flag. Defaults to off, making virtual but not durable collections.
|
|
@@ -84,12 +119,6 @@ export type DefineKindOptions<C> = {
|
|
|
84
119
|
*/
|
|
85
120
|
durable?: boolean;
|
|
86
121
|
|
|
87
|
-
/**
|
|
88
|
-
* If provided, it describes the shape of all state records of instances
|
|
89
|
-
* of this kind.
|
|
90
|
-
*/
|
|
91
|
-
stateShape?: StateShape;
|
|
92
|
-
|
|
93
122
|
/**
|
|
94
123
|
* Intended for internal use only.
|
|
95
124
|
* Should the raw methods receive their `context` argument as their first
|
|
@@ -28,8 +28,18 @@ import {
|
|
|
28
28
|
* @typedef {import('@endo/exo/src/exo-tools.js').KitContextProvider } KitContextProvider
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
hasOwn,
|
|
37
|
+
defineProperty,
|
|
38
|
+
getOwnPropertyNames,
|
|
39
|
+
values,
|
|
40
|
+
entries,
|
|
41
|
+
fromEntries,
|
|
42
|
+
} = Object;
|
|
33
43
|
const { ownKeys } = Reflect;
|
|
34
44
|
|
|
35
45
|
// Turn on to give each exo instance its own toStringTag value which exposes
|
|
@@ -679,6 +689,8 @@ export const makeVirtualObjectManager = (
|
|
|
679
689
|
const {
|
|
680
690
|
finish = undefined,
|
|
681
691
|
stateShape = undefined,
|
|
692
|
+
receiveAmplifier = undefined,
|
|
693
|
+
receiveInstanceTester = undefined,
|
|
682
694
|
thisfulMethods = false,
|
|
683
695
|
} = options;
|
|
684
696
|
let {
|
|
@@ -766,6 +778,11 @@ export const makeVirtualObjectManager = (
|
|
|
766
778
|
Fail`A stateShape must be a copyRecord: ${q(stateShape)}`;
|
|
767
779
|
assertPattern(stateShape);
|
|
768
780
|
|
|
781
|
+
if (!multifaceted) {
|
|
782
|
+
receiveAmplifier === undefined ||
|
|
783
|
+
Fail`Only facets of an exo class kit can be amplified, not ${q(tag)}`;
|
|
784
|
+
}
|
|
785
|
+
|
|
769
786
|
let facetNames;
|
|
770
787
|
|
|
771
788
|
if (isDurable) {
|
|
@@ -948,14 +965,20 @@ export const makeVirtualObjectManager = (
|
|
|
948
965
|
// and into method-invocation time (which is not).
|
|
949
966
|
|
|
950
967
|
let proto;
|
|
968
|
+
/** @type {ClassContextProvider | undefined} */
|
|
969
|
+
let contextProviderVar;
|
|
970
|
+
/** @type { Record<string, KitContextProvider> | undefined } */
|
|
971
|
+
let contextProviderKitVar;
|
|
972
|
+
|
|
951
973
|
if (multifaceted) {
|
|
952
|
-
|
|
953
|
-
const contextProviderKit = fromEntries(
|
|
974
|
+
contextProviderKitVar = fromEntries(
|
|
954
975
|
facetNames.map((name, index) => [
|
|
955
976
|
name,
|
|
956
977
|
rep => {
|
|
957
978
|
const vref = getSlotForVal(rep);
|
|
958
|
-
|
|
979
|
+
if (vref === undefined) {
|
|
980
|
+
return undefined;
|
|
981
|
+
}
|
|
959
982
|
const { baseRef, facet } = parseVatSlot(vref);
|
|
960
983
|
|
|
961
984
|
// Without this check, an attacker (with access to both
|
|
@@ -966,7 +989,9 @@ export const makeVirtualObjectManager = (
|
|
|
966
989
|
// objects, but they could invoke all their equivalent methods,
|
|
967
990
|
// by using e.g.
|
|
968
991
|
// cohort1.facetA.foo.apply(cohort2.facetB, [...args])
|
|
969
|
-
Number(facet)
|
|
992
|
+
if (Number(facet) !== index) {
|
|
993
|
+
return undefined;
|
|
994
|
+
}
|
|
970
995
|
|
|
971
996
|
return harden(contextCache.get(baseRef));
|
|
972
997
|
},
|
|
@@ -975,21 +1000,22 @@ export const makeVirtualObjectManager = (
|
|
|
975
1000
|
|
|
976
1001
|
proto = defendPrototypeKit(
|
|
977
1002
|
tag,
|
|
978
|
-
harden(
|
|
1003
|
+
harden(contextProviderKitVar),
|
|
979
1004
|
behavior,
|
|
980
1005
|
thisfulMethods,
|
|
981
1006
|
interfaceGuardKit,
|
|
982
1007
|
);
|
|
983
1008
|
} else {
|
|
984
|
-
|
|
985
|
-
const contextProvider = rep => {
|
|
1009
|
+
contextProviderVar = rep => {
|
|
986
1010
|
const slot = getSlotForVal(rep);
|
|
987
|
-
|
|
1011
|
+
if (slot === undefined) {
|
|
1012
|
+
return undefined;
|
|
1013
|
+
}
|
|
988
1014
|
return harden(contextCache.get(slot));
|
|
989
1015
|
};
|
|
990
1016
|
proto = defendPrototype(
|
|
991
1017
|
tag,
|
|
992
|
-
harden(
|
|
1018
|
+
harden(contextProviderVar),
|
|
993
1019
|
behavior,
|
|
994
1020
|
thisfulMethods,
|
|
995
1021
|
interfaceGuard,
|
|
@@ -997,6 +1023,10 @@ export const makeVirtualObjectManager = (
|
|
|
997
1023
|
}
|
|
998
1024
|
harden(proto);
|
|
999
1025
|
|
|
1026
|
+
// All this to let typescript know that it won't vary during a closure
|
|
1027
|
+
const contextProvider = contextProviderVar;
|
|
1028
|
+
const contextProviderKit = contextProviderKitVar;
|
|
1029
|
+
|
|
1000
1030
|
// this builds new Representatives, both when creating a new instance and
|
|
1001
1031
|
// for reanimating an existing one when the old rep gets GCed
|
|
1002
1032
|
|
|
@@ -1074,6 +1104,59 @@ export const makeVirtualObjectManager = (
|
|
|
1074
1104
|
return val;
|
|
1075
1105
|
};
|
|
1076
1106
|
|
|
1107
|
+
if (receiveAmplifier) {
|
|
1108
|
+
assert(contextProviderKit);
|
|
1109
|
+
|
|
1110
|
+
// Amplify a facet to a cohort
|
|
1111
|
+
const amplify = exoFacet => {
|
|
1112
|
+
for (const cp of values(contextProviderKit)) {
|
|
1113
|
+
const context = cp(exoFacet);
|
|
1114
|
+
if (context !== undefined) {
|
|
1115
|
+
return context.facets;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
throw Fail`Must be a facet of ${q(tag)}: ${exoFacet}`;
|
|
1119
|
+
};
|
|
1120
|
+
harden(amplify);
|
|
1121
|
+
receiveAmplifier(amplify);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
if (receiveInstanceTester) {
|
|
1125
|
+
if (multifaceted) {
|
|
1126
|
+
assert(contextProviderKit);
|
|
1127
|
+
|
|
1128
|
+
const isInstance = (exoFacet, facetName = undefined) => {
|
|
1129
|
+
if (facetName === undefined) {
|
|
1130
|
+
// Is exoFacet and instance of any facet of this class kit?
|
|
1131
|
+
return values(contextProviderKit).some(
|
|
1132
|
+
cp => cp(exoFacet) !== undefined,
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
// Is this exoFacet an instance of this specific facet column
|
|
1136
|
+
// of this class kit?
|
|
1137
|
+
assert.typeof(facetName, 'string');
|
|
1138
|
+
const cp = contextProviderKit[facetName];
|
|
1139
|
+
cp !== undefined ||
|
|
1140
|
+
Fail`exo class kit ${q(tag)} has no facet named ${q(facetName)}`;
|
|
1141
|
+
return cp(exoFacet) !== undefined;
|
|
1142
|
+
};
|
|
1143
|
+
harden(isInstance);
|
|
1144
|
+
receiveInstanceTester(isInstance);
|
|
1145
|
+
} else {
|
|
1146
|
+
assert(contextProvider);
|
|
1147
|
+
// Is this exo an instance of this class?
|
|
1148
|
+
const isInstance = (exo, facetName = undefined) => {
|
|
1149
|
+
facetName === undefined ||
|
|
1150
|
+
Fail`facetName can only be used with an exo class kit: ${q(
|
|
1151
|
+
tag,
|
|
1152
|
+
)} has no facet ${q(facetName)}`;
|
|
1153
|
+
return contextProvider(exo) !== undefined;
|
|
1154
|
+
};
|
|
1155
|
+
harden(isInstance);
|
|
1156
|
+
receiveInstanceTester(isInstance);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1077
1160
|
return makeNewInstance;
|
|
1078
1161
|
};
|
|
1079
1162
|
|
|
@@ -33,10 +33,12 @@ test('forbid cross-facet prototype attack', t => {
|
|
|
33
33
|
thing2.mutable.set(2);
|
|
34
34
|
|
|
35
35
|
t.throws(() => attack1(thing1.mutable, thing2.immutable), {
|
|
36
|
-
message:
|
|
36
|
+
message:
|
|
37
|
+
'"In \\"set\\" method of (thing mutable)" may only be applied to a valid instance: "[Alleged: thing immutable]"',
|
|
37
38
|
});
|
|
38
39
|
t.throws(() => attack2(thing1.mutable, thing2.immutable), {
|
|
39
|
-
message:
|
|
40
|
+
message:
|
|
41
|
+
'"In \\"set\\" method of (thing mutable)" may only be applied to a valid instance: "[Alleged: thing immutable]"',
|
|
40
42
|
});
|
|
41
43
|
t.is(thing1.immutable.get(), 1);
|
|
42
44
|
t.is(thing2.immutable.get(), 2);
|