Skip to content

Commit

Permalink
Merge pull request #3625 from Agoric/3442-activity-hash
Browse files Browse the repository at this point in the history
expose hash of kernel state changes as "activityhash"
  • Loading branch information
warner authored Aug 12, 2021
2 parents a277ae6 + 47ec86b commit b373c5a
Show file tree
Hide file tree
Showing 17 changed files with 399 additions and 138 deletions.
6 changes: 6 additions & 0 deletions packages/SwingSet/src/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { assert, details as X } from '@agoric/assert';
import { importBundle } from '@agoric/import-bundle';
import { xsnap, recordXSnap } from '@agoric/xsnap';

import { createSHA256 } from './hasher.js';
import engineGC from './engine-gc.js';
import { WeakRef, FinalizationRegistry } from './weakref.js';
import { startSubprocessWorker } from './spawnSubprocessWorker.js';
Expand Down Expand Up @@ -271,6 +272,7 @@ export async function makeSwingsetController(
WeakRef,
FinalizationRegistry,
gcAndFinalize: makeGcAndFinalize(engineGC),
createSHA256,
};

const kernelOptions = { verbose, warehousePolicy, overrideVatManagerOptions };
Expand Down Expand Up @@ -327,6 +329,10 @@ export async function makeSwingsetController(
return defensiveCopy(kernel.getStatus());
},

getActivityhash() {
return kernel.getActivityhash();
},

pinVatRoot(vatName) {
const vatID = kernel.vatNameToID(vatName);
const kref = kernel.getRootObject(vatID);
Expand Down
32 changes: 32 additions & 0 deletions packages/SwingSet/src/hasher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { assert } from '@agoric/assert';

import { createHash } from 'crypto';

/**
* @typedef { (initial: string?) => {
* add: (more: string) => void,
* finish: () => string,
* }
* } CreateSHA256
*/

/** @type { CreateSHA256 } */
function createSHA256(initial = undefined) {
const hash = createHash('sha256');
let done = false;
function add(more) {
assert(!done);
hash.update(more);
}
function finish() {
assert(!done);
done = true;
return hash.digest('hex');
}
if (initial) {
add(initial);
}
return harden({ add, finish });
}
harden(createSHA256);
export { createSHA256 };
14 changes: 6 additions & 8 deletions packages/SwingSet/src/kernel/initializeKernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import { makeMarshal, Far } from '@agoric/marshal';
import { assert, details as X } from '@agoric/assert';
import { createSHA256 } from '../hasher.js';
import { assertKnownOptions } from '../assertOptions.js';
import { insistVatID } from './id.js';
import { makeVatSlot } from '../parseVatSlots.js';
import { insistStorageAPI } from '../storageAPI.js';
import { wrapStorage } from './state/storageWrapper.js';
import makeKernelKeeper from './state/kernelKeeper.js';
import { exportRootObject, doQueueToKref } from './kernel.js';

Expand All @@ -16,12 +16,10 @@ function makeVatRootObjectSlot() {

export function initializeKernel(config, hostStorage, verbose = false) {
const logStartup = verbose ? console.debug : () => 0;
insistStorageAPI(hostStorage.kvStore);

const { kvStore, streamStore } = hostStorage;
insistStorageAPI(kvStore);
const { enhancedCrankBuffer, commitCrank } = wrapStorage(kvStore);

const kernelKeeper = makeKernelKeeper(enhancedCrankBuffer, streamStore);
const kernelSlog = null;
const kernelKeeper = makeKernelKeeper(hostStorage, kernelSlog, createSHA256);

const wasInitialized = kernelKeeper.getInitialized();
assert(!wasInitialized);
Expand Down Expand Up @@ -86,7 +84,7 @@ export function initializeKernel(config, hostStorage, verbose = false) {
const kref = exportRootObject(kernelKeeper, vatID);
// Pin, to prevent it being GC'd when only the kvStore points to it
kernelKeeper.pinObject(kref);
kvStore.set('vatAdminRootKref', kref);
kernelKeeper.kvStore.set('vatAdminRootKref', kref);
gotVatAdminRootKref = true;
}
}
Expand Down Expand Up @@ -135,7 +133,7 @@ export function initializeKernel(config, hostStorage, verbose = false) {
}
kernelKeeper.setInitialized();
kernelKeeper.saveStats();
commitCrank(); // commit initialized kernel state as crank #0
kernelKeeper.commitCrank(); // commit initialized kernel state as crank #0
return bootstrapResultKpid;

// ----------------------------------------------------------------------
Expand Down
28 changes: 9 additions & 19 deletions packages/SwingSet/src/kernel/kernel.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@ import { foreverPolicy } from '../runPolicies.js';
import { makeVatManagerFactory } from './vatManager/factory.js';
import { makeVatWarehouse } from './vatManager/vat-warehouse.js';
import makeDeviceManager from './deviceManager.js';
import { wrapStorage } from './state/storageWrapper.js';
import makeKernelKeeper from './state/kernelKeeper.js';
import { kdebug, kdebugEnable, legibilizeMessageArgs } from './kdebug.js';
import { insistKernelType, parseKernelSlot } from './parseKernelSlots.js';
import { parseVatSlot } from '../parseVatSlots.js';
import { insistStorageAPI } from '../storageAPI.js';
import { insistCapData } from '../capdata.js';
import { insistMessage, insistVatDeliveryResult } from '../message.js';
import { insistDeviceID, insistVatID } from './id.js';
Expand Down Expand Up @@ -128,6 +126,7 @@ export default function buildKernel(
WeakRef,
FinalizationRegistry,
gcAndFinalize,
createSHA256,
} = kernelEndowments;
deviceEndowments = { ...deviceEndowments }; // copy so we can modify
const {
Expand All @@ -138,25 +137,13 @@ export default function buildKernel(
} = kernelOptions;
const logStartup = verbose ? console.debug : () => 0;

const {
kvStore,
streamStore,
snapStore,
} = /** @type { HostStore } */ (hostStorage);
insistStorageAPI(kvStore);
const { enhancedCrankBuffer, abortCrank, commitCrank } = wrapStorage(kvStore);
const vatAdminRootKref = kvStore.get('vatAdminRootKref');
const vatAdminRootKref = hostStorage.kvStore.get('vatAdminRootKref');

const kernelSlog = writeSlogObject
? makeSlogger(slogCallbacks, writeSlogObject)
: makeDummySlogger(slogCallbacks, makeConsole);

const kernelKeeper = makeKernelKeeper(
enhancedCrankBuffer,
streamStore,
kernelSlog,
snapStore,
);
const kernelKeeper = makeKernelKeeper(hostStorage, kernelSlog, createSHA256);

let started = false;

Expand Down Expand Up @@ -261,7 +248,6 @@ export default function buildKernel(

const kernelSyscallHandler = makeKernelSyscallHandler({
kernelKeeper,
kvStore: enhancedCrankBuffer,
ephemeral,
// eslint-disable-next-line no-use-before-define
notify,
Expand Down Expand Up @@ -792,7 +778,7 @@ export default function buildKernel(
const { vatID, shouldReject, info } = terminationTrigger;
if (terminationTrigger.shouldAbortCrank) {
// errors unwind any changes the vat made
abortCrank();
kernelKeeper.abortCrank();
didAbort = true;
// but metering deductions and underflow notifications must survive
const { meterDeductions } = postAbortActions;
Expand All @@ -813,7 +799,7 @@ export default function buildKernel(
}
kernelKeeper.processRefcounts();
kernelKeeper.saveStats();
commitCrank();
kernelKeeper.commitCrank();
kernelKeeper.incrementCrankNumber();
} finally {
processQueueRunning = undefined;
Expand Down Expand Up @@ -1221,6 +1207,10 @@ export default function buildKernel(
});
},

getActivityhash() {
return kernelKeeper.getActivityhash();
},

dump() {
// note: dump().log is not deterministic, since log() does not go
// through the syscall interface (and we replay transcripts one vat at
Expand Down
3 changes: 2 additions & 1 deletion packages/SwingSet/src/kernel/kernelSyscall.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ export function doSend(kernelKeeper, target, msg) {
export function makeKernelSyscallHandler(tools) {
const {
kernelKeeper,
kvStore,
ephemeral,
notify,
doResolve,
setTerminationTrigger,
} = tools;

const { kvStore } = kernelKeeper;

function send(target, msg) {
return doSend(kernelKeeper, target, msg);
}
Expand Down
62 changes: 51 additions & 11 deletions packages/SwingSet/src/kernel/state/kernelKeeper.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// @ts-check
import { Nat } from '@agoric/nat';
import { assert, details as X } from '@agoric/assert';
import { wrapStorage } from './storageWrapper.js';
import { initializeVatState, makeVatKeeper } from './vatKeeper.js';
import { initializeDeviceState, makeDeviceKeeper } from './deviceKeeper.js';
import { parseReachableAndVatSlot } from './reachable.js';
import { insistEnhancedStorageAPI } from '../../storageAPI.js';
import {
insistStorageAPI,
insistEnhancedStorageAPI,
} from '../../storageAPI.js';
import {
insistKernelType,
makeKernelSlot,
Expand All @@ -27,6 +31,10 @@ const enableKernelGC = true;
// "prefix." and "prefix/", which avoids including anything using an
// extension of the prefix (e.g. [vat1.foo, vat1.bar, vat15.baz]).
//
// The 'local.' namespace is excluded from the kernel activity hash, and is
// allowed to vary between instances in a consensus machine. Everything else
// is required to be deterministic.
//
// The schema is:
//
// vat.names = JSON([names..])
Expand Down Expand Up @@ -55,13 +63,14 @@ const enableKernelGC = true;
// v$NN.vs.$key = string
// v$NN.meter = m$NN
// exclude from consensus
// v$NN.lastSnapshot = JSON({ snapshotID, startPos })
// local.v$NN.lastSnapshot = JSON({ snapshotID, startPos })

// m$NN.remaining = $NN // remaining capacity (in computrons) or 'unlimited'
// m$NN.threshold = $NN // notify when .remaining first drops below this

// exclude from consensus
// snapshot.$id = [vatID, ...]
// local.snapshot.$id = [vatID, ...]
// local.kernelStats // JSON(various kernel stats)

// d$NN.o.nextID = $NN
// d$NN.c.$kernelSlot = $deviceSlot = o-$NN/d+$NN/d-$NN
Expand Down Expand Up @@ -125,18 +134,41 @@ const FIRST_CRANK_NUMBER = 0n;
const FIRST_METER_ID = 1n;

/**
* @param {KVStorePlus} kvStore
* @param {StreamStore} streamStore
* @param {HostStore} hostStorage
* @param {KernelSlog} kernelSlog
* @param {SnapStore=} snapStore
* @param {import('../../hasher.js').CreateSHA256} createSHA256
*/
export default function makeKernelKeeper(
kvStore,
streamStore,
hostStorage,
kernelSlog,
snapStore = undefined,
createSHA256,
) {
// the kernelKeeper wraps the host's raw key-value store in a crank buffer
const rawKVStore = hostStorage.kvStore;
insistStorageAPI(rawKVStore);

/**
* @param { string } key
* @returns { boolean }
*/
function isConsensusKey(key) {
if (key.startsWith('local.')) {
return false;
}
return true;
}

const { abortCrank, commitCrank, enhancedCrankBuffer: kvStore } = wrapStorage(
rawKVStore,
createSHA256,
isConsensusKey,
);
insistEnhancedStorageAPI(kvStore);
const { streamStore, snapStore } = hostStorage;

function getActivityhash() {
return rawKVStore.get('activityhash');
}

/**
* @param {string} key
Expand Down Expand Up @@ -199,11 +231,14 @@ export default function makeKernelKeeper(
}

function saveStats() {
kvStore.set('kernelStats', JSON.stringify(kernelStats));
kvStore.set('local.kernelStats', JSON.stringify(kernelStats));
}

function loadStats() {
kernelStats = { ...kernelStats, ...JSON.parse(getRequired('kernelStats')) };
kernelStats = {
...kernelStats,
...JSON.parse(getRequired('local.kernelStats')),
};
}

function getStats() {
Expand Down Expand Up @@ -1329,6 +1364,11 @@ export default function makeKernelKeeper(
allocateDeviceIDForNameIfNeeded,
allocateDeviceKeeperIfNeeded,

kvStore,
abortCrank,
commitCrank,
getActivityhash,

dump,
});
}
Loading

0 comments on commit b373c5a

Please sign in to comment.