Skip to content

Commit

Permalink
saveAssetsMetadata
Browse files Browse the repository at this point in the history
  • Loading branch information
turbocrime committed Aug 5, 2024
1 parent c80bda2 commit bc2e1ff
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 56 deletions.
22 changes: 18 additions & 4 deletions packages/query/src/block-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,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 @@ -468,7 +472,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 Down Expand Up @@ -541,7 +549,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 @@ -563,7 +574,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
46 changes: 27 additions & 19 deletions packages/storage/src/indexed-db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,32 +63,39 @@ import {
DutchAuctionDescription,
} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/component/auction/v1/auction_pb.js';
import { ChainRegistryClient } from '@penumbra-labs/registry';
import { PartialMessage } from '@bufbuild/protobuf';
import { PartialMessage, PlainMessage } from '@bufbuild/protobuf';
import { getAmountFromRecord } from '@penumbra-zone/getters/spendable-note-record';
import { isZero } from '@penumbra-zone/types/amount';
import { IDB_VERSION } from './config.js';

const assertBytes = (v?: Uint8Array, expect?: number, name = 'value') => {
const assertBytes = (v?: Uint8Array, expect?: number, name = 'value'): v is Uint8Array => {
if (expect !== undefined && v?.length !== expect) {
throw new Error(`Expected ${name} of ${expect} bytes, but got ${v?.length} bytes`);
} else if (expect === undefined && !v?.length) {
throw new Error(`Expected ${name} to be non-empty, but got ${v?.length} bytes`);
}
return true;
};

// yes these are all 32 bytes
const assertAssetId = (assetId?: PartialMessage<AssetId>) =>
const assertAssetId = (assetId?: PartialMessage<AssetId>): assetId is PlainMessage<AssetId> =>
assertBytes(assetId?.inner, 32, 'AssetId');
const assertAuctionId = (auctionId?: PartialMessage<AuctionId>) =>
assertBytes(auctionId?.inner, 32, 'AuctionId');
const assertCommitment = (commitment?: PartialMessage<StateCommitment>) =>
const assertAuctionId = (
auctionId?: PartialMessage<AuctionId>,
): auctionId is PlainMessage<AuctionId> => assertBytes(auctionId?.inner, 32, 'AuctionId');
const assertCommitment = (
commitment?: PartialMessage<StateCommitment>,
): commitment is PlainMessage<StateCommitment> =>
assertBytes(commitment?.inner, 32, 'StateCommitment');
const assertNullifier = (nullifier?: PartialMessage<Nullifier>) =>
assertBytes(nullifier?.inner, 32, 'Nullifier');
const assertTransactionId = (txId?: PartialMessage<TransactionId>) =>
assertBytes(txId?.inner, 32, 'TransactionId');
const assertPositionId = (positionId?: PartialMessage<PositionId>) =>
assertBytes(positionId?.inner, 32, 'PositionId');
const assertNullifier = (
nullifier?: PartialMessage<Nullifier>,
): nullifier is PartialMessage<Nullifier> => assertBytes(nullifier?.inner, 32, 'Nullifier');
const assertTransactionId = (
txId?: PartialMessage<TransactionId>,
): txId is PartialMessage<TransactionId> => assertBytes(txId?.inner, 32, 'TransactionId');
const assertPositionId = (
positionId?: PartialMessage<PositionId>,
): positionId is PlainMessage<PositionId> => assertBytes(positionId?.inner, 32, 'PositionId');

interface IndexedDbProps {
chainId: string;
Expand Down Expand Up @@ -296,9 +303,12 @@ export class IndexedDb implements IndexedDbInterface {
);
}

async saveAssetsMetadata(metadata: Metadata) {
async saveAssetsMetadata(metadata: Required<PlainMessage<Metadata>>) {
assertAssetId(metadata.penumbraAssetId);
await this.u.update({ table: 'ASSETS', value: metadata.toJson() as Jsonified<Metadata> });
await this.u.update({
table: 'ASSETS',
value: new Metadata(metadata).toJson() as Jsonified<Metadata>,
});
}

// creates a local copy of the asset list from registry (https://github.com/prax-wallet/registry)
Expand All @@ -314,11 +324,9 @@ export class IndexedDb implements IndexedDbInterface {
}

const assets = registry.getAllAssets();
const saveLocalMetadata = assets.map(m => {
if (m.penumbraAssetId) {
this.saveAssetsMetadata(m);
}
});
const saveLocalMetadata = assets.map(m =>
this.saveAssetsMetadata({ ...m, penumbraAssetId: getAssetId(m) }),
);
await Promise.all(saveLocalMetadata);
await this.u.update({ table: 'REGISTRY_VERSION', key: 'commit', value: remoteVersion });
} catch (error) {
Expand Down
24 changes: 14 additions & 10 deletions packages/storage/src/indexed-db/indexed-db.test-data.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb.js';
import {
AssetId,
Metadata,
} from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb.js';
import {
SpendableNoteRecord,
SwapRecord,
Expand All @@ -13,6 +16,7 @@ import { TransactionId } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/
import { Transaction } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/transaction/v1/transaction_pb.js';
import type { ScanBlockResult } from '@penumbra-zone/types/state-commitment-tree';
import { base64ToUint8Array } from '@penumbra-zone/types/base64';
import { StateCommitment } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/crypto/tct/v1/tct_pb.js';

const hash3312332298 = base64ToUint8Array('JbOzRkf0VKm4eIM0DS27N5igX8jxvPhAMpBWSr2bj/Q=');

Expand Down Expand Up @@ -129,7 +133,7 @@ export const metadataA = Metadata.fromJson({
base: 'umars',
display: 'mars',
penumbraAssetId: { inner: 'fptGlCc8DHGYGzC0SGI9RJPkTcOhlwEgmTYlWKqG6RE=' },
});
}) as Metadata & { penumbraAssetId: AssetId };

export const metadataB = Metadata.fromJson({
denomUnits: [
Expand All @@ -140,7 +144,7 @@ export const metadataB = Metadata.fromJson({
base: 'ujupiter',
display: 'jupiter',
penumbraAssetId: { inner: 'tC8UkRa/CMAtIft8TgIHRTWS7D8KNA+nYlixMl0mYjU=' },
});
}) as Metadata & { penumbraAssetId: AssetId };

export const metadataC = Metadata.fromJson({
denom_units: [
Expand Down Expand Up @@ -170,7 +174,7 @@ export const metadataC = Metadata.fromJson({
alt_bech32m: '',
alt_base_denom: '',
},
});
}) as Metadata & { penumbraAssetId: AssetId };

export const delegationMetadataA = Metadata.fromJson({
denomUnits: [
Expand All @@ -189,7 +193,7 @@ export const delegationMetadataA = Metadata.fromJson({
base: 'udelegation_penumbravalid12s9lanucncnyasrsqgy6z532q7nwsw3aqzzeqas55kkpyf6lhsqs2w0zar',
display: 'delegation_penumbravalid12s9lanucncnyasrsqgy6z532q7nwsw3aqzzeqas55kkpyf6lhsqs2w0zar',
penumbraAssetId: { inner: '9gOwzeyGwav8YydzDGlEZyZkN8ITX2IerjVy0YjAIw8=' },
});
}) as Metadata & { penumbraAssetId: AssetId };

export const delegationMetadataB = Metadata.fromJson({
denomUnits: [
Expand All @@ -208,7 +212,7 @@ export const delegationMetadataB = Metadata.fromJson({
base: 'udelegation_penumbravalid15ex9m38fl5gv48vwszyhgsvp9q83wc7nl4z274u6atyfwtlaeqgqpjwkkm',
display: 'delegation_penumbravalid15ex9m38fl5gv48vwszyhgsvp9q83wc7nl4z274u6atyfwtlaeqgqpjwkkm',
penumbraAssetId: { inner: 'brSeAgTVPCTJsjLKNFWhRSnJOJQgumMRksEe34sJfgc=' },
});
}) as Metadata & { penumbraAssetId: AssetId };

export const newNote = SpendableNoteRecord.fromJson({
noteCommitment: {
Expand Down Expand Up @@ -243,7 +247,7 @@ export const newNote = SpendableNoteRecord.fromJson({
id: '3CBS08dM9eLHH45Z9loZciZ9RaG9x1fc26Qnv0lQlto=',
},
},
});
}) as SpendableNoteRecord & { noteCommitment: StateCommitment };

export const noteWithDelegationAssetA = SpendableNoteRecord.fromJson({
noteCommitment: { inner: 'n86D13I1rRUDoLCkX7LKl/AG8/F+2MV76p4XgPD++xA=' },
Expand All @@ -263,7 +267,7 @@ export const noteWithDelegationAssetA = SpendableNoteRecord.fromJson({
heightCreated: '43',
position: '2818048',
source: { transaction: { id: 'i++POrLfH1e5t+ys2ytLAJKi41HLt1s39Rj/bCFrMTI=' } },
});
}) as SpendableNoteRecord & { noteCommitment: StateCommitment };

export const noteWithDelegationAssetB = SpendableNoteRecord.fromJson({
noteCommitment: { inner: 'O5vXQyhaImbVKHuhpZqT5QYVA6HDlY4P+Hz/z3Xc5gU=' },
Expand All @@ -283,7 +287,7 @@ export const noteWithDelegationAssetB = SpendableNoteRecord.fromJson({
heightCreated: '53',
position: '3473408',
source: { transaction: { id: 'OVtt3KUg5v+yF/O/2pwE1/740EhFGZ3mK74LUvRfcL0=' } },
});
}) as SpendableNoteRecord & { noteCommitment: StateCommitment };

export const noteWithGmAsset = SpendableNoteRecord.fromJson({
noteCommitment: { inner: 'HPA48ggmSUsVVm5u871Y2qpURUZ60ic7/eL32ej0gQo=' },
Expand All @@ -303,7 +307,7 @@ export const noteWithGmAsset = SpendableNoteRecord.fromJson({
heightCreated: '17',
position: '1114112',
source: { transaction: { id: 'NNKqIUJRgSI1dS1VbWLNZeQpmQUG6pInn3sFqPNrFDA=' } },
});
}) as SpendableNoteRecord & { noteCommitment: StateCommitment };

export const transactionId = TransactionId.fromJson({
inner: '9MI8IG5D3MQj3s1j0MXTwCQtAaVbwTlPkW8Qdz1EVIo=',
Expand Down
Loading

0 comments on commit bc2e1ff

Please sign in to comment.