-
Notifications
You must be signed in to change notification settings - Fork 212
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
vat upgrade by replacing virtual-object behavior record #3062
Comments
Some version of upgrade is in the treasury launch critical path; this is the closest I can find. |
In today's kernel meeting we walked through some possibilities for upgrading the Treasury to fix a hypothetical bug in which some vaults ceased to allow close operations. In one approach, we declared that all upgradeable objects must be virtual. This gives us a principled way for the successor vat to provide replacement behavioral code for the predecessors exported objects (which the successor must honor, or revoke). In this case, we'd use virtual objects for low-cardinality (even singleton) objects too, not just for high-cardinality things. The predecessor must prepare for upgrade by registering each In this approach, any Remotables (other than the root object) cannot be replaced, since they aren't registered. I think it would be useful to be able to register and replace such Remotables, not just virtual objects, but I think @erights or @dtribble was keen on restricting that ability to virtual objects.. we need to discuss it more. |
As Norm says, there's always a bigger hammer. I'm keen on having a small well behaved hammer adequate for many "normal" upgrades, where we stay within the computational model, and the programmer intention on each side of the temporal boundary: The early programmer who prepares their contract's estates, keeps their affairs and will in order, so on the event of its sudden death, that estate is supposed to be adequate for the heir to pick up that state and resume operation. If we give the heir too much power to maybe potentially reconstruct from additional stuff that's lying around and may be helpful, the ancestor may be too willing to assume that the heir will find some way to cope. The next bigger hammer is when the ancestor, whether they made a good try or not, has failed to prepare an estate adequate for the heir to resume operation. The heir now has an emergency. We should find ways to help it cope with that emergency. But it is not the normal orderly transfer of operation. As we dive into the patterns and stores stuff, I'll explain the further distinction I think necessary between "virtual ephemeral" and "virtual persistent". Everything in the intended estate, to be communicated intentionally from ancestor to heir, must not only be virtual. It must be virtual persistent. The key difference is that non-virtual (and therefore necessarily ephemeral) things can be reached from virtual ephemeral. But with few exceptions, everything reachable from virtual persistent must not be local-non-virtual. It must be state that survives the ancestor's sudden death. |
@warner to refine the ticket. |
This implements the primary vat-side interface for upgrade (#4325, #4382). However, it does not yet implement the set of post upgrade checks (#3062) that will be required (e.g., check upon return from `buildRootObject` to verify that all the durable kinds have had behavior associated with them or have been explicitly dismissed); the ability to test or otherwise exercise the latter portion of the upgrade machinery will have to wait until the kernel-side interfaces (#1848, #3062) are in place. I am going to tentative declarely that this PR closes #4325, leaving the remaining work to be covered by #3062.
This implements the primary vat-side interface for upgrade (#4325, #4382). However, it does not yet implement the set of post upgrade checks (#3062) that will be required (e.g., check upon return from `buildRootObject` to verify that all the durable kinds have had behavior associated with them or have been explicitly dismissed); the ability to test or otherwise exercise the latter portion of the upgrade machinery will have to wait until the kernel-side interfaces (#1848, #3062) are in place. I am going to tentative declarely that this PR closes #4325, leaving the remaining work to be covered by #3062.
This implements the primary vat-side interface for upgrade (#4325, #4382). However, it does not yet implement the set of post upgrade checks (#3062) that will be required (e.g., check upon return from `buildRootObject` to verify that all the durable kinds have had behavior associated with them or have been explicitly dismissed); the ability to test or otherwise exercise the latter portion of the upgrade machinery will have to wait until the kernel-side interfaces (#1848, #3062) are in place. I am going to tentative declarely that this PR closes #4325, leaving the remaining work to be covered by #3062.
What is the Problem Being Solved?
@dtribble and I were brainstorming about upgrade pathways. I'm thinking of a taxonomy of upgrades, rated by depth/intricacy:
The first two can be accomplished by having some object in the vat code which knows the interest rate or function in question. Operations ask it for the rate every time, or the submit data to the function and get something back. The vat code which initially creates this will create a special facet that allows the value to be changed, and it will give this facet to a governance contract. A governance decision (using whatever voting mechanism that other contract cares for) can invoke the facet and give it a new number, or a new bundle of code to evaluate and overwrite the old function.
But the third one is interesting. As an example, think about an Issuer which has some (large) number of outstanding Purses, Payments, and DepositFacets. We want to change the implementation, but retain the validity of all those exported objects.
Description of the Design
@dtribble 's idea was to lean on the fact that we're representing all of those things as virtual objects. Each call to
makeKind()
is effectively creating a table, and providing both a behavior record and a function to create new rows. We'll need to give a name to each table: perhaps we add aname
argument tomakeKind
and we throw an error if it is not unique.Now, the upgraded vat wants to connect new behavior to the old records. So imagine a
vatPowers.replaceKind(name, behavior, initFunction)
that does mostly the same thing asmakeKind
but instead of allocating a new table, it re-uses an old one. We might add arguments which let the upgraded code know when it's being given an old record (maybe a version number along with eachstate
object), so it can react differently to the old data.To trigger this upgrade, we might use the
vatAdmin
facet and add a method which behaves like the "spawn zygote vat" API (#2268), except that it takes a new vat code bundle. When invoked, a new vatID is created, all the virtual-object exports of the old vat are re-targeted to point at the new one, all the non-virtual-object exports are left on the old vat, and the old vat is terminated. This would retain the identity of things which we can't carry over, they'd just be dead references (like exports of a terminated vat).For non-virtual exports that need to be retained, we could introduce a way to assign labels to certain exports (
vatPowers.nameExport('name', remotable)
), and then the new vat code could claim those exports (vatPowers.reconnectOldExport('name', newRemotable)
). We'd use this for contract entrypoints and root objects, things which are widely referenced singletons that aren't suitable for making into virtual objects. This might look a little bit like the #1692 "move" API.Security Considerations
We need to be super-careful about the authority patterns here. Arbitrary vat code should not be able to steal control over tables or previously-exported objects, so putting these powers on
vatPowers
(vsmakeKind
, which is ambient) makes it easier to the upgraded vat code to limit access.The text was updated successfully, but these errors were encountered: