Skip to content

Commit

Permalink
fix: pattern based compression on split reform
Browse files Browse the repository at this point in the history
  • Loading branch information
erights committed Nov 5, 2022
1 parent 0bf4739 commit f77aa27
Show file tree
Hide file tree
Showing 23 changed files with 975 additions and 171 deletions.
2 changes: 2 additions & 0 deletions packages/ERTP/src/paymentLedger.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const amountShapeFromElementShape = (brand, assetKind, elementShape) => {
if (elementShape === undefined) {
valueShape = M.arrayOf(M.key());
} else {
// M.and compresses only according to its last conjunct
valueShape = M.arrayOf(M.and(M.key(), elementShape));
}
break;
Expand Down Expand Up @@ -137,6 +138,7 @@ export const vivifyPaymentLedger = (
const paymentLedger = provideDurableWeakMapStore(
issuerBaggage,
'paymentLedger',
{ valueShape: amountShape },
);

/**
Expand Down
9 changes: 9 additions & 0 deletions packages/ERTP/src/purse.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { M } from '@agoric/store';
import { vivifyFarClassKit, makeScalarBigSetStore } from '@agoric/vat-data';
import { AmountMath } from './amountMath.js';
import { makeTransientNotifierKit } from './transientNotifier.js';
Expand All @@ -12,6 +13,8 @@ export const vivifyPurseKind = (
PurseIKit,
purseMethods,
) => {
const amountShape = brand.getAmountShape();

// Note: Virtual for high cardinality, but *not* durable, and so
// broken across an upgrade.
const { provideNotifier, update: updateBalance } = makeTransientNotifierKit();
Expand Down Expand Up @@ -111,6 +114,12 @@ export const vivifyPurseKind = (
},
},
},
{
stateShape: {
currentBalance: amountShape,
recoverySet: M.remotable('recoverySet'),
},
},
);
return () => makePurseKit().purse;
};
Expand Down
15 changes: 7 additions & 8 deletions packages/ERTP/test/unitTests/test-inputValidation.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ test('makeIssuerKit bad displayInfo.decimalPlaces', async t => {
harden({ decimalPlaces: 'hello' }),
),
{
message:
'displayInfo: optional: decimalPlaces: "hello" - Must be >= -100',
message: 'displayInfo: decimalPlaces?: "hello" - Must be >= -100',
},
);

Expand Down Expand Up @@ -62,15 +61,15 @@ test('makeIssuerKit bad displayInfo.decimalPlaces', async t => {
() =>
makeIssuerKit('myTokens', AssetKind.NAT, harden({ decimalPlaces: 101 })),
{
message: 'displayInfo: optional: decimalPlaces: 101 - Must be <= 100',
message: 'displayInfo: decimalPlaces?: 101 - Must be <= 100',
},
);

t.throws(
() =>
makeIssuerKit('myTokens', AssetKind.NAT, harden({ decimalPlaces: -101 })),
{
message: 'displayInfo: optional: decimalPlaces: -101 - Must be >= -100',
message: 'displayInfo: decimalPlaces?: -101 - Must be >= -100',
},
);
});
Expand All @@ -88,7 +87,7 @@ test('makeIssuerKit bad displayInfo.assetKind', async t => {
),
{
message:
'displayInfo: optional: assetKind: "something" - Must match one of ["nat","set","copySet","copyBag"]',
'displayInfo: assetKind?: "something" - Must match one of ["nat","set","copySet","copyBag"]',
},
);
});
Expand All @@ -105,7 +104,7 @@ test('makeIssuerKit bad displayInfo.whatever', async t => {
}),
),
{
message: 'displayInfo: rest: {"whatever":"something"} - Must be: {}',
message: 'displayInfo: ...rest: {"whatever":"something"} - Must be: {}',
},
);
});
Expand Down Expand Up @@ -142,7 +141,7 @@ test('brand.isMyIssuer bad issuer', async t => {
// @ts-expect-error Intentional wrong type for testing
t.throwsAsync(() => brand.isMyIssuer('not an issuer'), {
message:
'In "isMyIssuer" method of (myTokens brand): args: [0]: string "not an issuer" - Must be a remotable (Issuer)',
'In "isMyIssuer" method of (myTokens brand): arg 0: string "not an issuer" - Must be a remotable (Issuer)',
});
const fakeIssuer = /** @type {Issuer} */ (
/** @type {unknown} */ (Far('myTokens issuer', {}))
Expand Down Expand Up @@ -195,7 +194,7 @@ test('issuer.combine bad payments array', async t => {
// @ts-expect-error Intentional wrong type for testing
await t.throwsAsync(() => E(issuer).combine(notAnArray2), {
message:
'In "combine" method of (fungible issuer): args: [0]: remotable "[Alleged: notAnArray2]" - Must be a copyArray',
'In "combine" method of (fungible issuer): arg 0: remotable "[Alleged: notAnArray2]" - Must be a copyArray',
});
});

Expand Down
6 changes: 3 additions & 3 deletions packages/ERTP/test/unitTests/test-issuerObj.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ test('bad display info', t => {
const displayInfo = harden({ somethingUnexpected: 3 });
// @ts-expect-error deliberate invalid arguments for testing
t.throws(() => makeIssuerKit('fungible', AssetKind.NAT, displayInfo), {
message: 'displayInfo: rest: {"somethingUnexpected":3} - Must be: {}',
message: 'displayInfo: ...rest: {"somethingUnexpected":3} - Must be: {}',
});
});

Expand Down Expand Up @@ -200,7 +200,7 @@ test('purse.deposit promise', async t => {
() => E(purse).deposit(exclusivePaymentP, fungible25),
{
message:
'In "deposit" method of (fungible Purse purse): args: [0]: promise "[Promise]" - Must be a remotable (Payment)',
'In "deposit" method of (fungible Purse purse): arg 0: promise "[Promise]" - Must be a remotable (Payment)',
},
'failed to reject a promise for a payment',
);
Expand Down Expand Up @@ -335,7 +335,7 @@ test('issuer.split bad amount', async t => {
_ => E(issuer).split(payment, AmountMath.make(otherBrand, 10n)),
{
message:
'In "split" method of (fungible issuer): args: [1]: brand: "[Alleged: other fungible brand]" - Must be: "[Alleged: fungible brand]"',
'In "split" method of (fungible issuer): arg 1: brand: "[Alleged: other fungible brand]" - Must be: "[Alleged: fungible brand]"',
},
'throws for bad amount',
);
Expand Down
2 changes: 1 addition & 1 deletion packages/ERTP/test/unitTests/test-mintObj.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ test('mint.mintPayment set w strings AssetKind', async t => {
const badAmount = AmountMath.make(brand, harden([['badElement']]));
t.throws(() => mint.mintPayment(badAmount), {
message:
'In "mintPayment" method of (items mint): args: [0]: value: [0]: copyArray ["badElement"] - Must be a string',
'In "mintPayment" method of (items mint): arg 0: value: [0]: copyArray ["badElement"] - Must be a string',
});
});

Expand Down
52 changes: 30 additions & 22 deletions packages/SwingSet/src/liveslots/collectionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
assertKeyPattern,
assertPattern,
matches,
fit,
compareRank,
M,
zeroPad,
Expand All @@ -13,6 +14,8 @@ import {
isEncodedRemotable,
makeCopySet,
makeCopyMap,
mustCompress,
decompress,
} from '@agoric/store';
import { Far, passStyleOf } from '@endo/marshal';
import { decodeToJustin } from '@endo/marshal/src/marshal-justin.js';
Expand Down Expand Up @@ -213,7 +216,7 @@ export function makeCollectionManager(
return storeKindInfo[kindName].kindID;
}

// Not that it's only used for this purpose, what should it be called?
// Now that it's only used for this purpose, what should it be called?
// TODO Should we be using the new encodeBigInt scheme instead, anyway?
const BIGINT_TAG_LEN = 10;

Expand Down Expand Up @@ -257,6 +260,23 @@ export function makeCollectionManager(
const dbKeyPrefix = `vc.${collectionID}.`;
let currentGenerationNumber = 0;

const keyLabel = `invalid key type for collection ${q(label)}`;
const valueLabel = `invalid value type for collection ${q(label)}`;

const serializeValue = value => {
if (valueShape === undefined) {
return serialize(value);
}
return serialize(mustCompress(value, valueShape, valueLabel));
};

const unserializeValue = data => {
if (valueShape === undefined) {
return unserialize(data);
}
return decompress(unserialize(data), valueShape);
};

function prefix(dbEntryKey) {
return `${dbKeyPrefix}${dbEntryKey}`;
}
Expand Down Expand Up @@ -331,11 +351,10 @@ export function makeCollectionManager(
}

function get(key) {
matches(key, keyShape) ||
assert.fail(X`invalid key type for collection ${q(label)}`);
fit(key, keyShape, keyLabel);
const result = syscall.vatstoreGet(keyToDBKey(key));
if (result) {
return unserialize(JSON.parse(result));
return unserializeValue(JSON.parse(result));
}
assert.fail(X`key ${key} not found in collection ${q(label)}`);
}
Expand All @@ -351,16 +370,11 @@ export function makeCollectionManager(
}

function init(key, value) {
matches(key, keyShape) ||
assert.fail(X`invalid key type for collection ${q(label)}`);
fit(key, keyShape, keyLabel);
!has(key) ||
assert.fail(X`key ${key} already registered in collection ${q(label)}`);
if (valueShape) {
matches(value, valueShape) ||
assert.fail(X`invalid value type for collection ${q(label)}`);
}
const serializedValue = serializeValue(value);
currentGenerationNumber += 1;
const serializedValue = serialize(value);
assertAcceptableSyscallCapdataSize([serializedValue]);
if (durable) {
serializedValue.slots.forEach((vref, slotIndex) => {
Expand Down Expand Up @@ -388,13 +402,8 @@ export function makeCollectionManager(
}

function set(key, value) {
matches(key, keyShape) ||
assert.fail(X`invalid key type for collection ${q(label)}`);
if (valueShape) {
matches(value, valueShape) ||
assert.fail(X`invalid value type for collection ${q(label)}`);
}
const after = serialize(harden(value));
fit(key, keyShape, keyLabel);
const after = serializeValue(harden(value));
assertAcceptableSyscallCapdataSize([after]);
if (durable) {
after.slots.forEach((vref, i) => {
Expand All @@ -412,8 +421,7 @@ export function makeCollectionManager(
}

function deleteInternal(key) {
matches(key, keyShape) ||
assert.fail(X`invalid key type for collection ${q(label)}`);
fit(key, keyShape, keyLabel);
const dbKey = keyToDBKey(key);
const rawValue = syscall.vatstoreGet(dbKey);
assert(rawValue, X`key ${key} not found in collection ${q(label)}`);
Expand Down Expand Up @@ -472,7 +480,7 @@ export function makeCollectionManager(
if (dbKey < end) {
priorDBKey = dbKey;
if (ignoreKeys) {
const value = unserialize(JSON.parse(dbValue));
const value = unserializeValue(JSON.parse(dbValue));
if (matches(value, valuePatt)) {
yield [undefined, value];
}
Expand All @@ -484,7 +492,7 @@ export function makeCollectionManager(
} else {
const key = dbKeyToKey(dbKey);
if (matches(key, keyPatt)) {
const value = unserialize(JSON.parse(dbValue));
const value = unserializeValue(JSON.parse(dbValue));
if (matches(value, valuePatt)) {
yield [key, value];
}
Expand Down
Loading

0 comments on commit f77aa27

Please sign in to comment.