Skip to content

Commit

Permalink
Merge branch '16-persistence'
Browse files Browse the repository at this point in the history
Not yet complete, but good enough to merge.

refs Agoric#16
  • Loading branch information
warner committed Apr 2, 2019
2 parents bd7bcc7 + 46f622a commit 3157866
Show file tree
Hide file tree
Showing 30 changed files with 1,054 additions and 564 deletions.
14 changes: 6 additions & 8 deletions demo/contractHost/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@

import harden from '@agoric/harden';

export default function setup(syscall, helpers) {
const { E, dispatch, registerRoot } = helpers.makeLiveSlots(
syscall,
helpers.vatID,
);

function build(E) {
function mintTest(mint) {
console.log('starting mintTest');
const mP = E(mint).makeMint();
Expand Down Expand Up @@ -155,6 +150,9 @@ export default function setup(syscall, helpers) {
return undefined;
},
};
registerRoot(harden(obj0));
return dispatch;
return harden(obj0);
}

export default function setup(syscall, state, helpers) {
return helpers.makeLiveSlots(syscall, state, build, helpers.vatID);
}
9 changes: 2 additions & 7 deletions demo/contractHost/vat-alice.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,12 @@ function makeAlice(E, host) {
return alice;
}

export default function setup(syscall, helpers) {
const { E, dispatch, registerRoot } = helpers.makeLiveSlots(
syscall,
helpers.vatID,
);
registerRoot(
export default function setup(syscall, state, helpers) {
return helpers.makeLiveSlots(syscall, state, E =>
harden({
makeAlice(host) {
return harden(makeAlice(E, host));
},
}),
);
return dispatch;
}
9 changes: 2 additions & 7 deletions demo/contractHost/vat-bob.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,12 @@ function makeBob(E, host) {
return bob;
}

export default function setup(syscall, helpers) {
const { E, dispatch, registerRoot } = helpers.makeLiveSlots(
syscall,
helpers.vatID,
);
registerRoot(
export default function setup(syscall, state, helpers) {
return helpers.makeLiveSlots(syscall, state, E =>
harden({
makeBob(host) {
return harden(makeBob(E, host));
},
}),
);
return dispatch;
}
19 changes: 9 additions & 10 deletions demo/contractHost/vat-host.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,17 +143,16 @@ function makeHost(E) {
});
}

export default function setup(syscall, helpers) {
const { E, dispatch, registerRoot } = helpers.makeLiveSlots(
export default function setup(syscall, state, helpers) {
return helpers.makeLiveSlots(
syscall,
state,
E =>
harden({
makeHost() {
return harden(makeHost(E));
},
}),
helpers.vatID,
);
registerRoot(
harden({
makeHost() {
return harden(makeHost(E));
},
}),
);
return dispatch;
}
12 changes: 3 additions & 9 deletions demo/contractHost/vat-mint.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,9 @@ function build(_E) {
return harden({ mint });
}

return { makeMint };
return harden({ makeMint });
}

export default function setup(syscall, helpers) {
const { E, dispatch, registerRoot } = helpers.makeLiveSlots(
syscall,
helpers.vatID,
);
const obj0 = build(E);
registerRoot(harden(obj0));
return dispatch;
export default function setup(syscall, state, helpers) {
return helpers.makeLiveSlots(syscall, state, build, helpers.vatID);
}
23 changes: 11 additions & 12 deletions demo/left-right/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,23 @@ import harden from '@agoric/harden';

console.log(`loading bootstrap`);

export default function setup(syscall, helpers) {
export default function setup(syscall, state, helpers) {
function log(what) {
helpers.log(what);
console.log(what);
}
log(`bootstrap called`);
const { E, dispatch, registerRoot } = helpers.makeLiveSlots(
return helpers.makeLiveSlots(
syscall,
state,
E =>
harden({
bootstrap(argv, vats) {
E(vats.left)
.callRight(1, vats.right)
.then(r => log(`b.resolved ${r}`), err => log(`b.rejected ${err}`));
},
}),
helpers.vatID,
);
const obj0 = {
bootstrap(argv, vats) {
E(vats.left)
.callRight(1, vats.right)
.then(r => log(`b.resolved ${r}`), err => log(`b.rejected ${err}`));
},
};

registerRoot(harden(obj0));
return dispatch;
}
27 changes: 13 additions & 14 deletions demo/left-right/vat-left.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import harden from '@agoric/harden';

export default function setup(syscall, helpers) {
export default function setup(syscall, state, helpers) {
function log(what) {
helpers.log(what);
console.log(what);
}
const { E, dispatch, registerRoot } = helpers.makeLiveSlots(
return helpers.makeLiveSlots(
syscall,
state,
E =>
harden({
callRight(arg1, right) {
log(`left.callRight ${arg1}`);
E(right)
.bar(2)
.then(a => log(`left.then ${a}`));
return 3;
},
}),
helpers.vatID,
);

const t1 = {
callRight(arg1, right) {
log(`left.callRight ${arg1}`);
E(right)
.bar(2)
.then(a => log(`left.then ${a}`));
return 3;
},
};
registerRoot(harden(t1));
return dispatch;
}
22 changes: 11 additions & 11 deletions demo/left-right/vat-right.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import harden from '@agoric/harden';

export default function setup(syscall, helpers) {
export default function setup(syscall, state, helpers) {
function log(what) {
helpers.log(what);
console.log(what);
}
const { dispatch, registerRoot } = helpers.makeLiveSlots(

return helpers.makeLiveSlots(
syscall,
state,
_E =>
harden({
bar(arg2) {
log(`right ${arg2}`);
return 4;
},
}),
helpers.vatID,
);

const obj0 = {
bar(arg2) {
log(`right ${arg2}`);
return 4;
},
};
registerRoot(harden(obj0));
return dispatch;
}
10 changes: 10 additions & 0 deletions docs/persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,13 @@ To restore an entire kernel, we must:
* reconfigure the syscall object to hash and execute

Now the kernel should be back in the same state it had before. Every entry in the kernel's import/promise tables should match a Presence or Promise inside the corresponding Vat.

We can execute each Vat's transcript independently: the Vat's state will not depend upon what's happening in the other Vats, and the kernel's state won't depend upon what happens in this particular Vat (since we ignore syscalls during the replay, and compare hashes to make it emits the same syscalls that *were* executed last time).

Since syscalls can return values (e.g. a `send` returns a PromiseID for the answer), our Vat transcript must record these, so the same values can be returned during playback mode.

# more

The kernel's responsibility is to provide a persistence object to each vat userspace. Initially this will have a single get/set(string) pair of methods. Later, this will be more sophisticated, and will support a Merkle tree (of arbitrary arity) in which each child edge is named (or numbered) and either points to anoter node or a string (of JSON) (see IPFS for details). These nodes will provide an API with `has_child(index)`, `get_or_create_child_node(index)`, `delete_child(index)`, `set_child_data(index, data)`, `get_child_data(index)`. The vat gets access to a per-vat root node. By keeping track of which edges are followed by the vat, the kernel learns which data affects the computation, so it can construct an efficient proof for validators (i.e. the contents of every node that was visited, since the nodes contain the hashes of all their children (nodes or data). The only way to modify the tree is through the various set/delete APIs, so the kernel also learns which subset of the new tree data must be included in the proof.

Vat userspace is responsible for only depending upon state that comes from this persistence object, and for updating the persistence object with all state changes. The initial checkpoint+transcript state management approach will just JSON-serialize a list of turns (one dispatch, zero or more syscalls) and store the string into the initial get/set persistence object. We only actually need the results of the syscalls, but we store the full contents to double-check that the new code behaves the same way as the old code did.
13 changes: 11 additions & 2 deletions src/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import kernelSourceFunc from './bundles/kernel';
import buildKernelNonSES from './kernel/index';
import bundleSource from './build-source-bundle';

export function loadBasedir(basedir) {
export function loadBasedir(basedir, state) {
console.log(`= loading config from basedir ${basedir}`);
const vatSources = new Map();
const subs = fs.readdirSync(basedir, { withFileTypes: true });
Expand All @@ -37,7 +37,7 @@ export function loadBasedir(basedir) {
} catch (e) {
bootstrapIndexJS = undefined;
}
return harden({ vatSources, bootstrapIndexJS });
return harden({ vatSources, bootstrapIndexJS, state });
}

function getKernelSource() {
Expand Down Expand Up @@ -141,6 +141,10 @@ export async function buildVatController(config, withSES = true, argv = []) {
queueToExport(vatID, facetID, method, argsString) {
kernel.queueToExport(vatID, facetID, method, argsString, []);
},

getState() {
return JSON.parse(JSON.stringify(kernel.getState()));
},
});

if (config.vatSources) {
Expand All @@ -152,6 +156,11 @@ export async function buildVatController(config, withSES = true, argv = []) {

if (config.bootstrapIndexJS) {
await addVat('_bootstrap', config.bootstrapIndexJS);
}

if (config.state) {
await kernel.loadState(config.state);
} else if (config.bootstrapIndexJS) {
// we invoke obj[0].bootstrap with an object that contains 'vats' and
// 'argv'.
kernel.callBootstrap('_bootstrap', JSON.stringify(argv));
Expand Down
Loading

0 comments on commit 3157866

Please sign in to comment.