Skip to content
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

Rename vat-chainStorage to vat-bridge and make it upgradable #7107

Merged
merged 16 commits into from
Mar 22, 2023

Conversation

michaelfig
Copy link
Member

refs: #6553

Description

Based on #7057.

Both chain storage and the bridge manager are made durable, living in an upgradable vats/src/vat-bridge.js.

SwingSet changes should be reviewed by somebody from the kernel team.

Security Considerations

Usual security concerns and benefits with upgradability.

Scaling Considerations

All the usual durability concerns with disk vs. memory vs. cpu consumption.

Documentation Considerations

n/a

Testing Considerations

Null upgrade tests now also include basic functionality unit tests for the bridge and chain storage.

packages/vats/src/bridge.js Outdated Show resolved Hide resolved
@datadog-full-agoric
Copy link

datadog-full-agoric bot commented Mar 3, 2023

Datadog Report

Branch report: mfig-vat-bridge
Commit report: 6c2f6f8

agoric-sdk: 0 Failed, 0 New Flaky, 3560 Passed, 57 Skipped, 17m 5.14s Wall Time

packages/SwingSet/test/bootstrap-relay.js Outdated Show resolved Hide resolved
packages/SwingSet/test/bootstrap-relay.js Outdated Show resolved Hide resolved
packages/SwingSet/test/bootstrap-relay.js Outdated Show resolved Hide resolved
packages/internal/src/lib-chainStorage.js Outdated Show resolved Hide resolved
packages/internal/src/lib-chainStorage.js Outdated Show resolved Hide resolved
packages/vats/src/bridge.js Outdated Show resolved Hide resolved
packages/vats/src/bridge.js Outdated Show resolved Hide resolved
Comment on lines 15 to 21
const provideManagerForBridge = zoneBridgeManager(
zone.subZone('BridgeManager'),
D,
);
const makeChainStorageNode = zoneChainStorageNode(
zone.subZone('ChainStorageNode'),
);
Copy link
Member

@gibson042 gibson042 Mar 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that zoneBridgeManager starts with zone.subZone('ScopedManager').exoClass('BridgeScopedManager', …), zone.exoClassKit('BridgeManagerKit', …), and zone.mapStore('bridgeToManagerKit'); and that zoneChainStorageNode starts with zone.exoClass('ChainStorageNode', …), isn't this redundant nesting? I'd much rather see an arrangement in which all zone keys appear at the same (high) level. If we're not comfortable with representing specific MapStore keys as objects, perhaps instead we need a way to attenuate the zones?

Suggested change
const provideManagerForBridge = zoneBridgeManager(
zone.subZone('BridgeManager'),
D,
);
const makeChainStorageNode = zoneChainStorageNode(
zone.subZone('ChainStorageNode'),
);
const view = zone.attenuate({
keys: ['BridgeScopedManager', 'BridgeManagerKit', 'bridgeToManagerKit'],
});
const provideManagerForBridge = zoneBridgeManager(view, D);
const makeChainStorageNode = zoneChainStorageNode(view);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mechanism for attenuating the zones is to create a subzone. Attenuation based on filtering keys by name is discouraged because it is tightly coupled to the library using the zone, for which the specific key names are an implementation detail.

Your critique about redundant nesting for the subZone('ScopedManager') is a good one, though. I'll fix that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attenuation based on filtering keys by name is discouraged because it is tightly coupled to the library using the zone, for which the specific key names are an implementation detail.

Understood, but this cure seems worse than the disease. If I understand correctly, we're going to end up with baggage full of deeply nested but mostly empty maps, which will be unnecessarily difficult to debug:

MapStore{
  BridgeManager: MapStore{
    ScopedManager: MapStore{
      BridgeScopedManager_kindHandle: Far('kind', {}),
    },
    BridgeManagerKit_kindHandle: Far('kind', {}),
    bridgeToManagerKit: MapStore{…},
  },
  ChainStorageNode: MapStore{
    ChainStorageNode_kindHandle: Far('kind', {}),
  },
  …
}

while I think we should strive for something more like

MapStore{
  BridgeChannel_kindHandle: Far('kind', {}),
  BridgeManagerKit_kindHandle: Far('kind', {}),
  bridgeToManagerKit: MapStore{…},
  ChainStorageNode_kindHandle: Far('kind', {}),
  …
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a minor correction: I've already changed this so that there is no ScopedManager MapStore, which leaves the general structure 2 levels deep (first is controlled by the vat/contract initialization code with keys corresponding to packages, second is keys controlled by the individual package). Using subZones in this way is a straightforward (once documented) way to protect against one package stealing keys from another package.

If having 2 levels is still too difficult to debug, it is worth mentioning that the concept of a subZone doesn't inherently need to be implemented as deeply-nested maps. Another way forward could be to use a flat map with key prefixes to represent deep keys, somewhat like how you did with chainStorageNode.

MapStore{
  "BridgeManager:BridgeManagerKit_kindHandle": Far('kind', {}),
  "BridgeManager:BridgeScopedManager_kindHandle": Far('kind', {}),
  "BridgeManager:bridgeToManagerKit": MapStore{...},
  "ChainStorageNode:ChainStorageNode_kindHandle": Far('kind', {}),
  ...
}

Is either of these alternatives acceptable to you? Do they inspire you to propose something else?

Copy link
Member

@erights erights Mar 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand the problem

  • with nested sub-zones as attenuation. If another mechanism would not replace sub-zones, then it would seem to be unnecessary additional complexity. And I can't see how it could replace sub-zones.
  • with nested sub-zones resulting in nested baggage map-stores. Seems more straightforward than imposing a prefixing convention on flat names. Also, any string mangling system would need to worry about quoting confusion and hilbert, which we simply avoid by using nested maps.

We should probably have a verbal discussion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@erights We should keep in mind that the current state of sub-zones is insufficient to handle things that will definitely be needed, like limits for key counts, key length, entry depth, value size, and total data usage, and possibly even for things like key pattern. We can probably add all of that to sub-zones, but they may not turn out to be the right abstraction (for example, in a filesystem, directories are generally quite distinct from regular files and sometimes control is delegated at the level of a directory but other times it is at the level of one or more specific files—there's a reason why e.g. mktemp supports a --directory option rather than always creating a directory, even though single-file behavior is possible to implement on top of a directory-only foundation).

packages/vats/test/upgrading/test-upgrade-vats.js Outdated Show resolved Hide resolved
packages/vats/test/upgrading/device-bridge.js Outdated Show resolved Hide resolved
@datadog-full-agoric
Copy link

datadog-full-agoric bot commented Mar 14, 2023

Datadog Report

Branch report: mfig-vat-bridge
Commit report: 0d53cc3

agoric-sdk: 0 Failed, 0 New Flaky, 3774 Passed, 55 Skipped, 16m 41.03s Wall Time

@michaelfig michaelfig force-pushed the mfig-zones branch 2 times, most recently from 9b2697b to 46aae49 Compare March 15, 2023 18:00
@michaelfig michaelfig force-pushed the mfig-vat-bridge branch 2 times, most recently from f04c118 to c119eb2 Compare March 15, 2023 19:50
@mhofman mhofman removed their request for review March 15, 2023 23:19
@michaelfig michaelfig marked this pull request as ready for review March 17, 2023 15:58
Base automatically changed from mfig-zones to master March 19, 2023 23:01
Copy link
Member Author

@michaelfig michaelfig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the reviews, @gibson042! I've responded to or incorporated all your comments.

packages/SwingSet/test/bootstrap-relay.js Outdated Show resolved Hide resolved
* @param {Parameters<I>} args
* @returns {Promise<Awaited<ReturnType<I>>>}
*/
export const esend = (callback, ...args) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand this intuition, and in fact went out of my way to explore it, but there is a security boundary at play here.

If I use call(callback), I'm running the callback synchronously and so without proper care, it may interfere with my plans. If I use esend(callback), I'm protected by the async isolation guarantees that E(x) provides, regardless of the target of the callback.

Having said that, I acknowledge that the name call is terrible at conveying this. I think I will change it to callSync. I'm also thinking of changing esend to callE so that it rhymes and is reliant on E(target).

* one-off objects created with `Far()` or `makeExo()`
* instances created with a "make" function from `defineExoClass()`
* multifaceted kit instances created with a "makeKit" function from `defineExoClassKit()`

* Virtual objects in disk-based storage
* zone API found at `import { virtualZone } from '@agoric/zone/virtual.js';`
* instances created with a "make" function from `defineVirtualExoClass()`
* multifaceted kit instances created with a "makeKit" function from `defineVirtualExoClassKit()`
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New section to collect all the Zone documentation that was scattered around the previous section.

packages/zoe/tools/internal-types.js Outdated Show resolved Hide resolved
packages/zoe/tools/manualTimer.js Outdated Show resolved Hide resolved
packages/vats/src/bridge.js Outdated Show resolved Hide resolved
@datadog-full-agoric
Copy link

datadog-full-agoric bot commented Mar 22, 2023

Datadog Report

Branch report: mfig-vat-bridge
Commit report: 85e3347

agoric-sdk: 0 Failed, 0 New Flaky, 3790 Passed, 55 Skipped, 25m 32.23s Wall Time

Copy link
Member

@gibson042 gibson042 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but I am increasingly of the opinion that callSync is a footgun and should be removed. The typing in callback.js is quite a feat!

packages/vats/src/bridge.js Outdated Show resolved Hide resolved
packages/SwingSet/test/bootstrap-relay.js Outdated Show resolved Hide resolved
Comment on lines 3 to 6
* @property {(msg?: string) => ERef<void>} tick Advance the timer by one tick.
* DEPRECATED: use `await tickN(1)` instead. `tick` function errors might be
* thrown synchronously, even though success is signaled with `void` or
* `Promise<void>`.
Copy link
Member

@gibson042 gibson042 Mar 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm convinced by your desire to reserve ERef for inputs, and this can use JSDoc @deprecated.

Suggested change
* @property {(msg?: string) => ERef<void>} tick Advance the timer by one tick.
* DEPRECATED: use `await tickN(1)` instead. `tick` function errors might be
* thrown synchronously, even though success is signaled with `void` or
* `Promise<void>`.
* @deprecated Use `await tickN(1)` instead. `tick` function errors might be
* thrown synchronously, even though success is signaled by returning anything
* other than a rejected promise.
* @property {(msg?: string) => void | Promise<void>} tick Advance the timer by one tick.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, @deprecated only displays its doc string for a declaration it decorates, not a @property.

@codecov
Copy link

codecov bot commented Mar 22, 2023

Codecov Report

Merging #7107 (c1f757c) into master (4874362) will decrease coverage by 8.78%.
The diff coverage is 66.41%.

❗ Current head c1f757c differs from pull request most recent head 4b1a425. Consider uploading reports for the commit 4b1a425 to get more accurate results

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #7107      +/-   ##
==========================================
- Coverage   79.40%   70.62%   -8.78%     
==========================================
  Files         390      447      +57     
  Lines       73961    85077   +11116     
  Branches        3        3              
==========================================
+ Hits        58729    60088    +1359     
- Misses      15231    24923    +9692     
- Partials        1       66      +65     
Impacted Files Coverage Δ
packages/vats/src/bridge.js 25.68% <22.28%> (-5.43%) ⬇️
packages/internal/src/method-tools.js 58.18% <75.00%> (ø)
packages/internal/src/storage-test-utils.js 66.03% <75.00%> (+0.65%) ⬆️
packages/vats/src/core/chain-behaviors.js 86.27% <84.61%> (ø)
packages/SwingSet/src/controller/controller.js 96.42% <100.00%> (+0.01%) ⬆️
packages/SwingSet/src/vats/timer/vat-timer.js 99.58% <100.00%> (ø)
packages/internal/src/callback.js 100.00% <100.00%> (ø)
packages/internal/src/lib-chainStorage.js 95.29% <100.00%> (+1.21%) ⬆️
packages/vats/src/core/basic-behaviors.js 95.85% <100.00%> (ø)
packages/vats/src/core/startWalletFactory.js 50.31% <100.00%> (ø)
... and 2 more

... and 55 files with indirect coverage changes

Impacted file tree graph

@michaelfig michaelfig added the automerge:no-update (expert!) Automatically merge without updates label Mar 22, 2023
@mergify mergify bot merged commit 5933241 into master Mar 22, 2023
@mergify mergify bot deleted the mfig-vat-bridge branch March 22, 2023 22:40
gibson042 added a commit that referenced this pull request Mar 23, 2023
gibson042 added a commit that referenced this pull request Mar 23, 2023
gibson042 added a commit that referenced this pull request Mar 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:no-update (expert!) Automatically merge without updates contract-upgrade cosmic-swingset package: cosmic-swingset
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants