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

support changes to governed APIs #10822

Merged
merged 5 commits into from
Jan 22, 2025
Merged

support changes to governed APIs #10822

merged 5 commits into from
Jan 22, 2025

Conversation

Chris-Hibbert
Copy link
Contributor

@Chris-Hibbert Chris-Hibbert commented Jan 8, 2025

closes: #9990

Description

When a contract is upgraded, we'll read the governed APIs afresh.

Security Considerations

Nothing special. The point of governed APIs is that contracts can make access to calling specific APIs legible in the sense used by governance.

Scaling Considerations

Not an issue.

Documentation Considerations

If we had detailed documentation on governance, this would be worth adding to the docs.

Testing Considerations

Added a bootstrap test showing that a contract can be upgraded and the new APIs will be available after upgrade.

Upgrade Considerations

AssetReserve, fluxAggregator, and VaultFactory use apiGovernance and might need this support if any governed APIs were added.

Copy link

cloudflare-workers-and-pages bot commented Jan 9, 2025

Deploying agoric-sdk with  Cloudflare Pages  Cloudflare Pages

Latest commit: ffe2dd6
Status: ✅  Deploy successful!
Preview URL: https://90740884.agoric-sdk.pages.dev
Branch Preview URL: https://9990-upgradeapis.agoric-sdk.pages.dev

View logs

@Chris-Hibbert Chris-Hibbert force-pushed the 9990-upgradeAPIs branch 3 times, most recently from 0edc4ac to d1ec616 Compare January 15, 2025 00:24
@Chris-Hibbert Chris-Hibbert requested a review from dckc January 15, 2025 00:49
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.

Yes, I agree we should merge this.

How to validate it on a testnet in an upcoming release is sort of... interesting. It will have no impact until some governed contract gets upgraded. That might be in a later release. At that point, there would be a testing burden to verify that this fix works. But this issue won't be listed in the things we fixed for that later release. Seems like an acceptable risk.

The rest of my comments are sort of thinking out loud. Maybe I should keep them to myself... but I suppose I'll share anyway.

];

const setUpGovernedContract = async (zoe, timer, EV, controller) => {
const installBundle = contractBundle => EV(zoe).install(contractBundle);
Copy link
Member

Choose a reason for hiding this comment

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

Is it important to use .install(...) rather than .installBundleID(...)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope. They're equally useful AFAICT.

In order to understand, I looked at the docs, and realized they were out of date, so I created Agoric/documentation#1265.

add2: { outgoing: 'add2' },
};

let governedContract;
Copy link
Member

Choose a reason for hiding this comment

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

module level mutable state. hm. consider using a promise(kit) in t.context something like t.context.governedContractKit.promise and .resolver

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't mind module mutable state in a test. What javascript is missing here is write-once variables, but you're right that promises provide that ability. Done.

const agoricNamesAdmin =
await EV.vat('bootstrap').consumeItem('agoricNamesAdmin');
const instanceAdmin = await EV(agoricNamesAdmin).lookupAdmin('instance');
await EV(instanceAdmin).update('governedContract', instance);
Copy link
Member

Choose a reason for hiding this comment

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

I wonder why we're adding governedContract to agoricNames.instance

Copy link
Contributor Author

Choose a reason for hiding this comment

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

[I don't have good terminology for this. I welcome cleaner solutions.]

I needed an object with getKref() to pass to governanceDriver.proposeApiCall(). Storing the object in agoricNames, and retrieving it withEV was the only path I found that worked.

If it had been a substantive contract, storing the instance in agoricNames would have been a reasonable thing to do, and it would have had a more plausible name. j

Comment on lines 194 to 195
// Far side-effects the object, and can only be applied once
const farGovernedApis = Far('governedAPIs', governedApis);
Copy link
Member

Choose a reason for hiding this comment

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

after thinking about this a bit, it's probably OK as is. But I'll leave some breadcrumbs...

can we make it the caller's responsibility to mark it Far? Making the record in one place and marking it Far in another is odd.

One possibility is to make a new record...

Suggested change
// Far side-effects the object, and can only be applied once
const farGovernedApis = Far('governedAPIs', governedApis);
// Far side-effects the object, and can only be applied once
const farGovernedApis = Far('governedAPIs', { ... governedApis });

Copy link
Contributor Author

Choose a reason for hiding this comment

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

One possibility is to make a new record...

Thanks. That's a much better answer.

Comment on lines 498 to 500
} catch (e) {
Fail`restartContract failed: original contract facets were not durable`;
}
Copy link
Member

Choose a reason for hiding this comment

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

Is it really the case that the only exception possible is that the facets were not durable? I suppose so... zcfBaggage.get(...) is the only thing in the try.

But if get(...) had a bug, we might lose diagnostic info here. It feels weird to throw away e completely.
log it?

Copy link
Member

Choose a reason for hiding this comment

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

Do we support something like this?

Suggested change
} catch (e) {
Fail`restartContract failed: original contract facets were not durable`;
}
} catch (e) {
throw assert.error(`restartContract failed: original contract facets were not durable`, { cause: e });
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In what way would that be better?

I think Fail gets us an error, a stack, and messages visible in logs. I don't know what throw assert.error() could add to that. Whatever assert.error() does, I wouldn't expect it to return something that would be useful to throw, but I certainly don't know for sure.

Copy link
Member

Choose a reason for hiding this comment

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

In what way would that be better?

It doesn't throw away the details of e. Note especially { cause: e }

@@ -0,0 +1,311 @@
import { test as anyTest } from '@agoric/swingset-vat/tools/prepare-test-env-ava.js';
Copy link
Member

Choose a reason for hiding this comment

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

it's a little hard to see the forest for the trees.

Part of me would like the uninteresting stuff moved to a separate file, but then I'd have to jump back and forth.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, of course.
(rhetorical) Why didn't yarn lint warn me about an unused variable?
I can't easily add that to my pre-check script, since it's just a grep pattern.

@Chris-Hibbert Chris-Hibbert added the automerge:rebase Automatically rebase updates, then merge label Jan 22, 2025
Copy link
Contributor

mergify bot commented Jan 22, 2025

This pull request has been removed from the queue for the following reason: checks failed.

The merge conditions cannot be satisfied due to failing checks:

You should look at the reason for the failure and decide if the pull request needs to be fixed or if you want to requeue it.

If you want to requeue this pull request, you need to post a comment with the text: @mergifyio requeue

@mergify mergify bot merged commit f5bf658 into master Jan 22, 2025
83 checks passed
@mergify mergify bot deleted the 9990-upgradeAPIs branch January 22, 2025 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:rebase Automatically rebase updates, then merge contract-upgrade Governance Governance
Projects
None yet
Development

Successfully merging this pull request may close these issues.

API governance captures governed APIs at initial creation, doesn't notice upgrades
2 participants