Skip to content

Commit

Permalink
assert lengths of binary field inputs to idb methods (#1639)
Browse files Browse the repository at this point in the history
* assert lengths of binary input to idb
* type idb methods to require keypath inputs
* fix: correctly process compact block gas prices (#1637)
  • Loading branch information
turbocrime authored Aug 5, 2024
1 parent 457e04f commit bd43d49
Show file tree
Hide file tree
Showing 16 changed files with 256 additions and 95 deletions.
5 changes: 5 additions & 0 deletions .changeset/beige-files-promise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@penumbra-zone/storage': minor
---

assert binary input dimensions
6 changes: 6 additions & 0 deletions .changeset/good-ligers-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@penumbra-zone/storage': minor
'@penumbra-zone/types': minor
---

require complete GasPrices input to saveGasPrices
5 changes: 5 additions & 0 deletions .changeset/modern-wombats-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@penumbra-zone/getters': patch
---

add export getAssetIdFromGasPrices
5 changes: 5 additions & 0 deletions .changeset/strong-games-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@penumbra-zone/query': patch
---

correctly save gas prices from compact block
4 changes: 4 additions & 0 deletions packages/getters/src/compact-block.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { GasPrices } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/fee/v1/fee_pb.js';
import { createGetter } from './utils/create-getter.js';

export const getAssetIdFromGasPrices = createGetter((gp?: GasPrices) => gp?.assetId);
4 changes: 4 additions & 0 deletions packages/getters/src/spendable-note-record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ export const getAssetIdFromRecord = createGetter(
export const getAmountFromRecord = createGetter(
(noteRecord?: SpendableNoteRecord) => noteRecord?.note?.value?.amount,
);

export const getSpendableNoteRecordCommitment = createGetter(
(note?: SpendableNoteRecord) => note?.noteCommitment,
);
78 changes: 59 additions & 19 deletions packages/query/src/block-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ import { processActionDutchAuctionEnd } from './helpers/process-action-dutch-auc
import { processActionDutchAuctionSchedule } from './helpers/process-action-dutch-auction-schedule.js';
import { processActionDutchAuctionWithdraw } from './helpers/process-action-dutch-auction-withdraw.js';
import { RootQuerier } from './root-querier.js';
import { GasPrices } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/fee/v1/fee_pb.js';
import { IdentityKey } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1/keys_pb.js';
import { getDelegationTokenMetadata } from '@penumbra-zone/wasm/stake';
import { toPlainMessage } from '@bufbuild/protobuf';
import { getAssetIdFromGasPrices } from '@penumbra-zone/getters/compact-block';
import { getSpendableNoteRecordCommitment } from '@penumbra-zone/getters/spendable-note-record';
import { getSwapRecordCommitment } from '@penumbra-zone/getters/swap-record';

declare global {
// eslint-disable-next-line no-var
Expand All @@ -56,6 +59,16 @@ declare global {
var __ASSERT_ROOT__: boolean | undefined;
}

const isSwapRecordWithSwapCommitment = (
r?: unknown,
): r is Exclude<SwapRecord, { swapCommitment: undefined }> =>
r instanceof SwapRecord && r.swapCommitment instanceof StateCommitment;

const isSpendableNoteRecordWithNoteCommitment = (
r?: unknown,
): r is Exclude<SpendableNoteRecord, { noteCommitment: undefined }> =>
r instanceof SpendableNoteRecord && r.noteCommitment instanceof StateCommitment;

interface QueryClientProps {
querier: RootQuerier;
indexedDb: IndexedDbInterface;
Expand Down Expand Up @@ -169,16 +182,17 @@ export class BlockProcessor implements BlockProcessorInterface {
await this.indexedDb.saveFmdParams(compactBlock.fmdParameters);
}
if (compactBlock.gasPrices) {
await this.indexedDb.saveGasPrices(
new GasPrices({
assetId: this.stakingAssetId,
...compactBlock.gasPrices,
}),
);
await this.indexedDb.saveGasPrices({
...toPlainMessage(compactBlock.gasPrices),
assetId: toPlainMessage(this.stakingAssetId),
});
}
if (compactBlock.altGasPrices.length) {
for (const gasPrice of compactBlock.altGasPrices) {
await this.indexedDb.saveGasPrices(gasPrice);
for (const altGas of compactBlock.altGasPrices) {
await this.indexedDb.saveGasPrices({
...toPlainMessage(altGas),
assetId: getAssetIdFromGasPrices(altGas),
});
}
}

Expand Down Expand Up @@ -352,10 +366,16 @@ export class BlockProcessor implements BlockProcessorInterface {

private async saveRecoveredCommitmentSources(recovered: (SpendableNoteRecord | SwapRecord)[]) {
for (const record of recovered) {
if (record instanceof SpendableNoteRecord) {
await this.indexedDb.saveSpendableNote(record);
} else if (record instanceof SwapRecord) {
await this.indexedDb.saveSwap(record);
if (isSpendableNoteRecordWithNoteCommitment(record)) {
await this.indexedDb.saveSpendableNote({
...toPlainMessage(record),
noteCommitment: toPlainMessage(getSpendableNoteRecordCommitment(record)),
});
} else if (isSwapRecordWithSwapCommitment(record)) {
await this.indexedDb.saveSwap({
...toPlainMessage(record),
swapCommitment: toPlainMessage(getSwapRecordCommitment(record)),
});
} else {
throw new Error('Unexpected record type');
}
Expand Down Expand Up @@ -445,7 +465,11 @@ export class BlockProcessor implements BlockProcessorInterface {
const isIbcAsset = metadataFromNode && assetPatterns.ibc.matches(metadataFromNode.display);

if (metadataFromNode && !isIbcAsset) {
await this.indexedDb.saveAssetsMetadata(customizeSymbol(metadataFromNode));
const customized = customizeSymbol(metadataFromNode);
await this.indexedDb.saveAssetsMetadata({
...customized,
penumbraAssetId: getAssetId(customized),
});
return metadataFromNode;
}

Expand All @@ -466,7 +490,11 @@ export class BlockProcessor implements BlockProcessorInterface {

const generatedMetadata = getDelegationTokenMetadata(identityKey);

await this.indexedDb.saveAssetsMetadata(customizeSymbol(generatedMetadata));
const customized = customizeSymbol(generatedMetadata);
await this.indexedDb.saveAssetsMetadata({
...customized,
penumbraAssetId: getAssetId(customized),
});
return generatedMetadata;
}

Expand All @@ -486,10 +514,16 @@ export class BlockProcessor implements BlockProcessorInterface {

if (record instanceof SpendableNoteRecord) {
record.heightSpent = height;
await this.indexedDb.saveSpendableNote(record);
await this.indexedDb.saveSpendableNote({
...toPlainMessage(record),
noteCommitment: toPlainMessage(getSpendableNoteRecordCommitment(record)),
});
} else if (record instanceof SwapRecord) {
record.heightClaimed = height;
await this.indexedDb.saveSwap(record);
await this.indexedDb.saveSwap({
...toPlainMessage(record),
swapCommitment: toPlainMessage(getSwapRecordCommitment(record)),
});
}
}

Expand Down Expand Up @@ -539,7 +573,10 @@ export class BlockProcessor implements BlockProcessorInterface {
if (action.case === 'positionOpen' && action.value.position) {
for (const state of POSITION_STATES) {
const metadata = getLpNftMetadata(computePositionId(action.value.position), state);
await this.indexedDb.saveAssetsMetadata(metadata);
await this.indexedDb.saveAssetsMetadata({
...metadata,
penumbraAssetId: getAssetId(metadata),
});
}
// to optimize on-chain storage PositionId is not written in the positionOpen action,
// but can be computed via hashing of immutable position fields
Expand All @@ -561,7 +598,10 @@ export class BlockProcessor implements BlockProcessorInterface {
sequence: action.value.sequence,
});
const metadata = getLpNftMetadata(action.value.positionId, positionState);
await this.indexedDb.saveAssetsMetadata(metadata);
await this.indexedDb.saveAssetsMetadata({
...metadata,
penumbraAssetId: getAssetId(metadata),
});

await this.indexedDb.updatePosition(action.value.positionId, positionState);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@ import {
} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb.js';
import { IndexedDbInterface } from '@penumbra-zone/types/indexed-db';

const inner0123 = Uint8Array.from({ length: 32 }, () => Math.floor(Math.random() * 256));
const inner4567 = Uint8Array.from({ length: 32 }, () => Math.floor(Math.random() * 256));

vi.mock('@penumbra-zone/wasm/auction', () => ({
getAuctionNftMetadata: () => new Metadata({ display: 'penumbra' }),
getAuctionNftMetadata: () =>
Metadata.fromJson({
penumbraAssetId: { inner: 'ARpgNbcWB8SkCuCBjlTsW8eDmEqeJQGWYDhbUk3Q1pc=' },
display: 'test',
}),
}));

describe('processActionDutchAuctionEnd()', () => {
Expand All @@ -23,7 +30,7 @@ describe('processActionDutchAuctionEnd()', () => {
upsertAuction: Mock;
addAuctionOutstandingReserves: Mock;
};
const auctionId = new AuctionId({ inner: new Uint8Array([0, 1, 2, 3]) });
const auctionId = new AuctionId({ inner: inner0123 });
const action = new ActionDutchAuctionEnd({ auctionId });

beforeEach(() => {
Expand All @@ -45,13 +52,13 @@ describe('processActionDutchAuctionEnd()', () => {
);

expect(indexedDb.saveAssetsMetadata).toHaveBeenCalledWith(
expect.objectContaining({ display: 'penumbra' }),
expect.objectContaining({ display: 'test' }),
);
});

it('upserts the auction with the sequence number', async () => {
const inputAssetId = new AssetId({ inner: new Uint8Array([0, 1, 2, 3]) });
const outputAssetId = new AssetId({ inner: new Uint8Array([4, 5, 6, 7]) });
const inputAssetId = new AssetId({ inner: inner0123 });
const outputAssetId = new AssetId({ inner: inner4567 });

auctionQuerier.auctionStateById.mockResolvedValueOnce(
new DutchAuction({
Expand Down Expand Up @@ -81,8 +88,8 @@ describe('processActionDutchAuctionEnd()', () => {
});

it('adds the auction reserves', async () => {
const inputAssetId = new AssetId({ inner: new Uint8Array([0, 1, 2, 3]) });
const outputAssetId = new AssetId({ inner: new Uint8Array([4, 5, 6, 7]) });
const inputAssetId = new AssetId({ inner: inner0123 });
const outputAssetId = new AssetId({ inner: inner4567 });

auctionQuerier.auctionStateById.mockResolvedValueOnce(
new DutchAuction({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ActionDutchAuctionEnd,
DutchAuction,
} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb.js';
import { getAssetId } from '@penumbra-zone/getters/metadata';
import { IndexedDbInterface } from '@penumbra-zone/types/indexed-db';
import { AuctionQuerierInterface } from '@penumbra-zone/types/querier';
import { getAuctionNftMetadata } from '@penumbra-zone/wasm/auction';
Expand Down Expand Up @@ -40,7 +41,7 @@ export const processActionDutchAuctionEnd = async (
};

await Promise.all([
indexedDb.saveAssetsMetadata(metadata),
indexedDb.saveAssetsMetadata({ ...metadata, penumbraAssetId: getAssetId(metadata) }),
indexedDb.upsertAuction(action.auctionId, { seqNum }),
indexedDb.addAuctionOutstandingReserves(action.auctionId, outstandingReserves),
]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DutchAuctionDescription } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb.js';
import { getAssetId } from '@penumbra-zone/getters/metadata';
import { IndexedDbInterface } from '@penumbra-zone/types/indexed-db';
import { getAuctionId, getAuctionNftMetadata } from '@penumbra-zone/wasm/auction';

Expand All @@ -14,7 +15,7 @@ export const processActionDutchAuctionSchedule = async (
const metadata = getAuctionNftMetadata(auctionId, seqNum);

await Promise.all([
indexedDb.saveAssetsMetadata(metadata),
indexedDb.saveAssetsMetadata({ ...metadata, penumbraAssetId: getAssetId(metadata) }),
indexedDb.upsertAuction(auctionId, {
auction: description,
seqNum,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AuctionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb.js';
import { getAssetId } from '@penumbra-zone/getters/metadata';
import { IndexedDbInterface } from '@penumbra-zone/types/indexed-db';
import { getAuctionNftMetadata } from '@penumbra-zone/wasm/auction';

Expand All @@ -10,7 +11,7 @@ export const processActionDutchAuctionWithdraw = async (
const metadata = getAuctionNftMetadata(auctionId, seqNum);

await Promise.all([
indexedDb.saveAssetsMetadata(metadata),
indexedDb.saveAssetsMetadata({ ...metadata, penumbraAssetId: getAssetId(metadata) }),
indexedDb.upsertAuction(auctionId, {
seqNum,
}),
Expand Down
3 changes: 2 additions & 1 deletion packages/services/src/view-service/asset-metadata-by-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { servicesCtx } from '../ctx/prax.js';
import { assetPatterns } from '@penumbra-zone/types/assets';
import { getAssetPriorityScore } from './util/asset-priority-score.js';
import { customizeSymbol } from '@penumbra-zone/wasm/metadata';
import { getAssetId } from '@penumbra-zone/getters/metadata';

export const assetMetadataById: Impl['assetMetadataById'] = async ({ assetId }, ctx) => {
if (!assetId) {
Expand Down Expand Up @@ -41,7 +42,7 @@ export const assetMetadataById: Impl['assetMetadataById'] = async ({ assetId },

if (remoteMetadata && !isIbcAsset) {
const customized = customizeSymbol(remoteMetadata);
void indexedDb.saveAssetsMetadata(customized);
void indexedDb.saveAssetsMetadata({ ...customized, penumbraAssetId: getAssetId(customized) });
return { denomMetadata: customized };
}

Expand Down
Loading

0 comments on commit bd43d49

Please sign in to comment.