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

6678 assetRegistry through walletFactory upgrade #7111

Merged
merged 6 commits into from
Mar 7, 2023

Conversation

turadg
Copy link
Member

@turadg turadg commented Mar 4, 2023

closes: #6878

Description

6878 issue said,

It will have to hold the issuers from before upgrade. This can be done using ZCF saveIssuer and let the ZCF be responsible for its durability. The MapStore to BrandDescription need not be durable since it's part of shared made in prepare.

This doesn't do that but it adds a test to verify that it isn't necessary. A Bank's getAssetSubscription comes from a SubscriptionKit which uses a pinnedHistoryTopic which is prefix lossy.

// The publish kit subscriber is prefix-lossy, so making *this* subscriber completely
// lossless from initialisation requires pinning the former's history.
const pinnedHistoryTopic = makePinnedHistoryTopic(subscriber);

So each time an observeIteration is started with it, all the values will be consumed. Therefore the contract doesn't need to keep a history of them. On upgrade it reconstructs its non-durable maps using the stream.

To test this I tried to check use vstorage to confirm the offers execute, but the "secondOffer" one wasn't showing up. I don't know why and didn't want to spend too much time down that rabbit hole. Instead I made executeOffer throw its exceptions after trying to recover from it. (I think we had a handler to ensure there was always cleanup but it also swallowed the error unnecessarily.)

This uncovered a bug in the runUtils with calls after a rejection. This fixes that as well.

Security Considerations

--

Scaling Considerations

If there are many kinds of assets, walletFactory upgrade will triggeer iterating over all of them. I expect it to be order 10 until this contract is upgraded.

Documentation Considerations

--

Testing Considerations

New test

@turadg turadg changed the base branch from master to 6878-walletFactory-upgrade March 4, 2023 00:52
Base automatically changed from 6878-walletFactory-upgrade to master March 4, 2023 01:24
@turadg turadg force-pushed the 6678-walletFactory-assetRegistry branch from 8c12623 to 71a1db7 Compare March 6, 2023 22:42
@datadog-full-agoric
Copy link

datadog-full-agoric bot commented Mar 6, 2023

Datadog Report

Branch report: 6678-walletFactory-assetRegistry
Commit report: 8d27301

agoric-sdk: 0 Failed, 0 New Flaky, 3659 Passed, 57 Skipped, 14m 36.23s Wall Time

@turadg turadg changed the title 6678 walletFactory assetRegistry 6678 assetRegistry through walletFactory upgrade Mar 6, 2023
@turadg turadg requested review from dckc and Chris-Hibbert March 6, 2023 23:00
@turadg turadg force-pushed the 6678-walletFactory-assetRegistry branch from 71a1db7 to e4c984b Compare March 6, 2023 23:15
@turadg turadg marked this pull request as ready for review March 6, 2023 23:16
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.

Looks pretty much good to go,

but I need to be sure the bridge protocol doesn't do something drastic like crashing the kernel when a bridge call throws / rejects.

await tryBody().catch(err => handleError(err));
await tryBody().catch(err => {
handleError(err);
// propagate to caller
Copy link
Member

Choose a reason for hiding this comment

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

If the caller is a bridge handler, I'm not sure throwing is allowed. Is there something higher up that deals with that?

Copy link
Member Author

Choose a reason for hiding this comment

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

PTAL 71314fe

want: {},
},
});
await t.throwsAsync(
Copy link
Member

Choose a reason for hiding this comment

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

👍

},
proposal: {},
}),
{ message: '"nameKey" not found: "not-present"' },
Copy link
Member

Choose a reason for hiding this comment

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

nameKey here should be instance, I think. (orthogonal to this PR)

Copy link
Member Author

Choose a reason for hiding this comment

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

proposal: {},
}),
{
message: 'target has no method "makeGiveMintedInvitation ", has []',
Copy link
Member

Choose a reason for hiding this comment

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

the has [] is likely to change when #6570 is fixed.

* Make a registry for use by the wallet instances.
*
* This doesn't need to persist durably because the `assetPublisher` has a
* "pinned" topic and call togetAssetSubscription gets a fresh stream of all the
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* "pinned" topic and call togetAssetSubscription gets a fresh stream of all the
* "pinned" topic and call to getAssetSubscription gets a fresh stream of all the


({ bank } = makeFakeBankKit([]));
);
zoePK.resolve(zoeService);
Copy link
Member

Choose a reason for hiding this comment

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

😄


return true;
},

testOfferV1: async () => {
// If this doesn't throw, the offer succeeded.
// I tried to also check vstorage but it doesn't always update in time.
Copy link
Member

Choose a reason for hiding this comment

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

yeah... lack of a return promise from setValue makes coordinating that sort of thing nearly impossible.

@@ -72,8 +71,11 @@ test('bridge handler', async t => {
),
blockTime: 0,
blockHeight: 0,
};
assert(t.context.sendToBridge);
await t.throwsAsync(t.context.sendToBridge(validMsg), {
Copy link
Member

Choose a reason for hiding this comment

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

again, I'd like to be sure the bridge protocol doesn't do something drastic like crashing the kernel when a bridge call throws / rejects.

Copy link
Member

Choose a reason for hiding this comment

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

ok... found it. Nothing drastic. Just an unhandled rejection.

void scopedManagers.get(srcID).fromBridge(obj);

Copy link
Contributor

@Chris-Hibbert Chris-Hibbert left a comment

Choose a reason for hiding this comment

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

The upgrade test changes look fine to me. The rest of it flew right past me.

@dckc do you know what it's about?

want: {},
},
});
await t.throwsAsync(
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are some of the t.throwsAsync() calls missing a message to match?

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 started adding them after a bit. The errors messages are tested by the vstorage check.

If we commit to this throing from executeOffer, I can take out the redundant vstorage checks and have a test focused on vstorage writing out when there's an error. The different errors needn't all be checked in vstorage.

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.

@dckc do you know what it's about?

yes. @turadg landed a large part of walletFactory upgrade in an earlier PR. This remaining part takes care of a notifier (by deciding that it doesn't need to be durable).

*/
handleBridgeAction(actionCapData, canSpend = false) {
const { publicMarshaller } = shared;

const { offers } = this.facets;

return E.when(
E.when(
Copy link
Member

Choose a reason for hiding this comment

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

should be void E.when(?

@@ -171,7 +175,7 @@ export const prepare = async (zcf, privateArgs, baggage) => {
const wallet = walletsByAddress.get(obj.owner); // or throw

console.log('walletFactory:', { wallet, actionCapData });
return E(wallet).handleBridgeAction(actionCapData, canSpend);
E(wallet).handleBridgeAction(actionCapData, canSpend);
Copy link
Member

@mhofman mhofman Mar 7, 2023

Choose a reason for hiding this comment

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

Surprised this doesn't need a void prefix, E(foo).bar() will always return a promise.

Copy link
Member Author

Choose a reason for hiding this comment

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

Doesn't affect runtime and doesn't affect CI unless AGORIC_ESLINT_TYPES is enabled. But it's not #5788

You're right it would be better and I ran locally with that enabled to catch these:
Screenshot 2023-03-06 at 4 42 46 PM

Amending and force pushing now.

@@ -171,7 +175,7 @@ export const prepare = async (zcf, privateArgs, baggage) => {
const wallet = walletsByAddress.get(obj.owner); // or throw

console.log('walletFactory:', { wallet, actionCapData });
return E(wallet).handleBridgeAction(actionCapData, canSpend);
E(wallet).handleBridgeAction(actionCapData, canSpend);
Copy link
Member

Choose a reason for hiding this comment

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

add void?

* { updated: 'balance'; currentAmount: Amount }
* @typedef {{ updated: 'offerStatus', status: import('./offers.js').OfferStatus }
* | { updated: 'balance'; currentAmount: Amount }
* | { updated: 'bridgeStatus'; status: { error: string } }
Copy link
Member

Choose a reason for hiding this comment

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

This seem like an abstraction leak to mention "bridge"

Copy link
Member Author

Choose a reason for hiding this comment

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

how so? the smartWallet contract relies on a Cosmos bridge. we've even considered renaming this contract to have bridge in the name.

is there something else you'd suggest?

Copy link
Member

Choose a reason for hiding this comment

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

I mean that if this is a value that is exposed to the Wallet UI app, does it make sense for it to be aware that the implementation on chain uses something called a "bridge". The way I see it, it should just know it's sending a "wallet spend action", and how that's routed internally is not its concern. This effectively reifies that implementation detail.

Copy link
Member

@mhofman mhofman Mar 7, 2023

Choose a reason for hiding this comment

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

Does executeOffer update offerStatus in all cases of rejections? If so, I'd be willing to leave the unhandled rejection for the default case (unknown method).

Copy link
Member Author

Choose a reason for hiding this comment

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

Deferring to #7004

@turadg turadg force-pushed the 6678-walletFactory-assetRegistry branch from 37e0d49 to a5664b7 Compare March 7, 2023 18:53
@turadg turadg force-pushed the 6678-walletFactory-assetRegistry branch from a5664b7 to 770b2bf Compare March 7, 2023 19:16
@turadg turadg added the automerge:no-update (expert!) Automatically merge without updates label Mar 7, 2023
@mergify mergify bot merged commit 0ac8eb2 into master Mar 7, 2023
@mergify mergify bot deleted the 6678-walletFactory-assetRegistry branch March 7, 2023 19:51
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.

make the smart wallet factory contract upgradable
4 participants