-
Notifications
You must be signed in to change notification settings - Fork 208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(vats): upgradeable board #6903
Conversation
d9ab429
to
2b73dfe
Compare
2b73dfe
to
5ec107a
Compare
@warner @gibson042 @FUDCo I'd like to add a virtualization test that shows that heap size stays flat even with many items added to the board. Any suggestions on how to go about it? |
953ce44
to
cab791f
Compare
@@ -1521,7 +1521,6 @@ export function makeWalletRoot({ | |||
return E(board) | |||
.getValue(boardId) | |||
.then(value => { | |||
// @ts-expect-error type is too specific |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I take it this is from the string template thing and not an implicit any
53579b6
to
9b600df
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made the changes I proposed
9b600df
to
ffe52ee
Compare
* @param {import('@agoric/vat-data').Baggage} baggage | ||
*/ | ||
export function buildRootObject(_vatPowers, _vatParameters, baggage) { | ||
const makeBoardKit = prepareBoardKit(baggage); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think anything accepting a baggage argument to write into should also accept a key rather than hard-coding it.
const makeBoardKit = prepareBoardKit(baggage); | |
const makeBoardKit = prepareBoardKit(baggage, 'Board'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disagree, but I see an extensive internal slack discussion, so will continue there. Whatever the outcome, someone should publicly summarize.
@@ -49,6 +49,14 @@ test('makeBoard', async t => { | |||
t.is(idObj2b, 'tooboard012'); | |||
}); | |||
|
|||
test('board values must be scalar keys', async t => { | |||
const board = makeBoard(); | |||
const nonKey = harden({ a: 1 }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get more test coverage here? Array, symbol, number, bigint, boolean, etc.?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like the patterns API is reasonably well tested elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, so what exactly is this testing? The "invalid key type" error seems to come from collectionManager.js, which means that the bad input was accepted by the method guard, which suggests to me that ValShape
in packages/vats/src/lib-board.js should be M.scalar()
rather than M.key()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Digging deeper, I think this hits an issue that was apparently not caught by testing: makeScalarBigMapStore
(the function that makes durable maps such as baggage, sometimes through provideDurableMapStore
) is built on makeCollection
, which defaults to a keyShape of M.scalar()
. But if a board's values can be anything matched by M.key()
, then it's valToId map should be specified with a corresponding keyShape of M.key()
or else it won't actually be able to support non-scalar values (which seems like the testing gap here).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, non-scalar keys are not yet implemented by *MapStore
and *SetStore
. We make the "Scalar" qualifier explicit in the maker names to emphasize that these implement only a subset of the full MapStore and SetStore semantics.
Non-scalar keys are implemented by CopyMap, CopySet, and CopyBag.
So whether the correct restriction to express is M.key()
or M.scalar()
depends on if you're trying to detect a violation of the specified semantics, or a violation of the current implementation restrictions. Either way, please put a comment at the relevant place in the code to explain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, non-scalar keys are not yet implemented by
*MapStore
and*SetStore
.
Hmm, then it seems like a problem for e.g. makeScalarBigMapStore("dummy", { keyShape: M.key() }).init(harden({ label: "not a scalar" }), "val")
to succeed (which it currently does, at least in isolation). But more importantly, doesn't that restriction make Board durability (and thus upgradability) an order of magnitude more challenging? How should it store the value-to-id data if not in a durable map?
We make the "Scalar" qualifier explicit in the maker names to emphasize that these implement only a subset of the full MapStore and SetStore semantics.
D'oh! I should have picked up on/remembered that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
makeScalarBigMapStore("dummy", { keyShape: M.key() }).init(harden({ label: "not a scalar" }), "val")
succeeds? Really? That is very surprising. Are you sure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$ node --input-type=module -e '
import "@agoric/swingset-vat/tools/prepare-test-env.js";
import { M } from "@agoric/store";
import { makeScalarBigMapStore } from "@agoric/vat-data";
const bigMap = makeScalarBigMapStore("dummy", { keyShape: M.key() });
const key = harden({ label: "not a scalar" });
bigMap.init(key, "val");
console.log(bigMap.get(key));
'
val
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@erights I don't think we're that lucky; more likely the in-memory implementation set up for testing is just not very restrictive and the keyShape
argument for makeScalarBigMapStore
et al. is treated as a replacement for the M.scalar()
default rather than a refinement of it. And assertKeyPattern(M.key())
passes, although I don't know whether or not that's appropriate because there's some mismatch between checkKeyPattern
vs. checkKey
(the former rejecting non-scalar specimens like harden({})
but not Matchers like the "match:key" tagged record returned from M.key()
because checkKeyPattern
internally delegates checking of a tagged record specimen that is a Matcher to the checkKeyPattern
method of the corresponding matchHelper from HelpersByMatchTag
, which for "match:key" accepts all input).
EDIT: Having explored that, I think something is indeed amiss in checkKeyPattern
.
6a15f95
to
7c9355e
Compare
It failed deployment-test due to GH's Ubuntu brownout which lasts for another couple hours. This doesn't change the behavior of vat-update so I am betting on it not affecting deployment-test and have added a |
@Mergifyio requeue |
conflicts with type from `E(board).getId()`, now that getId is declared to return string rather than defaulting to any docs(board): BoardId description
- add docs - exo class kit shaped board w/marshallers - interface guards - factor out makeMarshallers() - re-work makeBoard() based on prepareBoardClass() - ./types.js import not needed - new makeSimpleRemote in boot-relay
7c9355e
to
4ec36bf
Compare
refs: #6553
Description
Use the
prepareExoClassKit
pattern make board state virtual, durable, and heritable by upgrade successors.Marshallers are
provide
d ephemerally, keyed bythis
.Security Considerations
Interface guards tighten things up a bit.
Scaling Considerations
on
getId(val)
:Documentation Considerations
Since this was my first (non-trivial) work with the virtual, durable, upgrade APIs, I tried to leave cookie crumbs.
Since I touched so much code, I added external API documentation to
lib-board.js
while I was at it.Testing Considerations
1 happy-path null upgrade test seemed sufficient to force me to get VDO / upgrade stuff right.
test-lib-board.js
came in quite handy for testing interface guards and making sure I didn't break the marshal stuff.I added 1 test to be more explicit that values have to be passable keys.