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

feat(cosmic-swingset): Add a config property for exporting storage to bootstrap #7489

Merged
merged 6 commits into from
Apr 25, 2023

Conversation

gibson042
Copy link
Member

Fixes #7156

Description

When SwingSet configuration includes exportStorageSubtrees, read all chain storage data at or under the specified paths and make the resulting array of entries available to the bootstrap vat at parameter chainStorageEntries.

Security Considerations

None known; launch-chain already had access to the bridge and control over configuration is already a highly privileged capability.

Scaling Considerations

Reading the data can potentially be very slow, but we have accepted that.

Documentation Considerations

I'm not sure where chain configuration and bootstrap vat parameters are officially documented, but would welcome suggestions.

Testing Considerations

There doesn't seem to be any existing test framework that could verify the new behavior. 😢

@gibson042 gibson042 requested review from mhofman and dckc April 24, 2023 16:34
@dckc
Copy link
Member

dckc commented Apr 24, 2023

re testing... is it straightforward / cost-effective to mock bridgeOutbound? I suppose this new code would have to be hoisted to its own exported function too. hm.

Copy link
Member

@dckc dckc left a comment

Choose a reason for hiding this comment

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

the code looks plausible. And nailing down the name chainStorageEntries is handy for coordination with #6645

But I hesitate to approve without a test. I'd like to think about that a bit more.

Copy link
Member

@dckc dckc left a comment

Choose a reason for hiding this comment

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

I guess I'm willing to take the risk and go without an automated test.

Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

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

This may be out of scope for this PR, but I think we should fix the underlying vstorage "entries" method. cc @michaelfig

Besides that, just some nits in comments.

packages/SwingSet/src/types-external.js Outdated Show resolved Hide resolved
Comment on lines 190 to 191
* (e.g., `exportStorageSubtrees: ['a.b']` might result in vatParameters including
* `chainStorageEntries: [ ['a.b', ''], ['a.b.c', '"foo"'], ['a.b.c2', '42'] ]`).
Copy link
Member

Choose a reason for hiding this comment

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

It would also include descendant that are not direct children, e.g. ['a.b.c3.d', 'foo'].

Comment on lines +128 to +139
const callChainStorage = (method, path) =>
bridgeOutbound(BRIDGE_ID.STORAGE, { method, args: [path] });
Copy link
Member

Choose a reason for hiding this comment

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

I imagined we would extend makePrefixedBridgeStorage instead of manually minting chain sends, but I guess there is no need for such abstractions.

packages/SwingSet/src/types-external.js Outdated Show resolved Hide resolved
@gibson042 gibson042 requested a review from mhofman April 25, 2023 02:21
Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

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

Thanks so much for adding these vstorage unit tests.

I missed it the first time around, but I think we need to add the custom prefix used by chain-storage. I don't want bootstrap to possibly get full access to the root vstorage, which contains the kernel state, etc.

Comment on lines 74 to 75
keeper.SetStorage(ctx, types.NewStorageEntry("empty", ""))
keeper.SetStorage(ctx, types.NewStorageEntryWithNoData("special.nodata"))
Copy link
Member

Choose a reason for hiding this comment

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

nit: I'd prefer if the test was more realistic and no data entries only existed for cases where there are nested entries

Suggested change
keeper.SetStorage(ctx, types.NewStorageEntry("empty", ""))
keeper.SetStorage(ctx, types.NewStorageEntryWithNoData("special.nodata"))
keeper.SetStorage(ctx, types.NewStorageEntry("placeholder.empty", ""))
keeper.SetStorage(ctx, types.NewStorageEntryWithNoData("placeholder"))

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed (in both places).

Comment on lines 262 to 270
keeper.SetStorage(ctx, types.NewStorageEntry("key1", "value1"))
keeper.SetStorage(ctx, types.NewStorageEntry("key1.child1.grandchild1", "value1grandchild"))
keeper.SetStorage(ctx, types.NewStorageEntryWithNoData("key1.child1.grandchild2"))
keeper.SetStorage(ctx, types.NewStorageEntry("key1.child1.empty-non-terminal.leaf", ""))
keeper.SetStorage(ctx, types.NewStorageEntry("key2.child2.grandchild2", "value2grandchild"))
keeper.SetStorage(ctx, types.NewStorageEntry("key2.child2.grandchild2a", "value2grandchilda"))
Copy link
Member

Choose a reason for hiding this comment

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

Same nit about representative test data

Suggested change
keeper.SetStorage(ctx, types.NewStorageEntry("key1", "value1"))
keeper.SetStorage(ctx, types.NewStorageEntry("key1.child1.grandchild1", "value1grandchild"))
keeper.SetStorage(ctx, types.NewStorageEntryWithNoData("key1.child1.grandchild2"))
keeper.SetStorage(ctx, types.NewStorageEntry("key1.child1.empty-non-terminal.leaf", ""))
keeper.SetStorage(ctx, types.NewStorageEntry("key2.child2.grandchild2", "value2grandchild"))
keeper.SetStorage(ctx, types.NewStorageEntry("key2.child2.grandchild2a", "value2grandchilda"))
keeper.SetStorage(ctx, types.NewStorageEntry("key1", "value1"))
keeper.SetStorage(ctx, types.NewStorageEntry("key1.child1.grandchild1", "value1grandchild"))
keeper.SetStorage(ctx, types.NewStorageEntryWithNoData("key1.child1"))
keeper.SetStorage(ctx, types.NewStorageEntry("key1.child1.empty-non-terminal.leaf", ""))
keeper.SetStorage(ctx, types.NewStorageEntryWithNoData("key2"))
keeper.SetStorage(ctx, types.NewStorageEntryWithNoData("key2.child2"))
keeper.SetStorage(ctx, types.NewStorageEntry("key2.child2.grandchild2", "value2grandchild"))
keeper.SetStorage(ctx, types.NewStorageEntry("key2.child2.grandchild2a", "value2grandchilda"))

Comment on lines 144 to 145
const fullPath =
!path || path === '.' ? `${nextSegment}` : `${path}.${nextSegment}`;
Copy link
Member

Choose a reason for hiding this comment

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

I believe path === '.' is invalid and I'm tempted to say we should disallow path from ever being empty in the initial "get"

Suggested change
const fullPath =
!path || path === '.' ? `${nextSegment}` : `${path}.${nextSegment}`;
const fullPath =`${path}.${nextSegment}`;

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 interface doesn't currently allow enumerating top-level keys AFAICT, and that seems like a problem that could be addressed at some point—but in ignorance of this consumer. This anticipates and accommodates either a DNS-like . or an even more simple empty-string fix.

However, I think you're right about needing to require STORAGE_PATH.CUSTOM so it will be moot.

Comment on lines +133 to +144
const value = callChainStorage('get', path);
return [path, value];
Copy link
Member

Choose a reason for hiding this comment

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

I believe you need to prepend STORAGE_PATH.CUSTOM

Suggested change
const value = callChainStorage('get', path);
return [path, value];
const fullPath = `${STORAGE_PATH.CUSTOM}.${path}`;
const value = callChainStorage('get', fullPath);
return [fullPath, value];

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've asked for confirmation, but I think we should keep that prefix explicit—albeit with enforcement.

@gibson042
Copy link
Member Author

Okay @mhofman, back to you.

@gibson042 gibson042 requested a review from mhofman April 25, 2023 16:46
Copy link
Member

@mhofman mhofman left a comment

Choose a reason for hiding this comment

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

LGTM

func TestEntries(t *testing.T) {
kit := makeTestKit()
keeper, handler, ctx, cctx := kit.keeper, kit.handler, kit.ctx, kit.cctx

keeper.SetStorage(ctx, types.NewStorageEntry("key1", "value1"))
keeper.SetStorage(ctx, types.NewStorageEntry("key1.child1.grandchild1", "value1grandchild"))
keeper.SetStorage(ctx, types.NewStorageEntryWithNoData("key1.child1.grandchild2"))
Copy link
Member

Choose a reason for hiding this comment

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

Curious why we need to test this case as it's not supposed to ever happen.

Copy link
Member Author

Choose a reason for hiding this comment

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

Robust handling if that ever changes (or better yet, a failure in this test).

@gibson042 gibson042 added the automerge:no-update (expert!) Automatically merge without updates label Apr 25, 2023
@gibson042 gibson042 force-pushed the gibson-7156-bootstrap-chainstorage-export branch from d375995 to 4f1589c Compare April 25, 2023 18:19
@mergify mergify bot merged commit 88491d2 into master Apr 25, 2023
@mergify mergify bot deleted the gibson-7156-bootstrap-chainstorage-export branch April 25, 2023 18:59
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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Provide PSM chainStorage data to Bulldozer bootstrap
3 participants