Skip to content

Commit

Permalink
Support ANY parsing w/ registry
Browse files Browse the repository at this point in the history
  • Loading branch information
grod220 committed Sep 24, 2024
1 parent 63c2686 commit 8e9bc8c
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 59 deletions.
2 changes: 1 addition & 1 deletion apps/minifront/src/components/tx-details/tx-viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const TxViewer = ({ txInfo }: { txInfo?: TransactionInfo }) => {

// use React-Query to invoke custom hooks that call async translators.
const { data: receiverView } = useQuery(
['receiverView', txInfo, option],
['receiverView', txInfo?.toJson({ typeRegistry }), option],
() =>
fetchReceiverView(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- TODO: justify
Expand Down
9 changes: 0 additions & 9 deletions packages/protobuf/src/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import * as penumbraCore from './services/penumbra-core.js';
import * as penumbraCustody from './services/penumbra-custody.js';
import * as penumbraUtil from './services/penumbra-util.js';
import * as penumbraView from './services/penumbra-view.js';

import { MsgRecvPacket } from '../gen/ibc/core/channel/v1/tx_pb.js';
import { MsgUpdateClient } from '../gen/ibc/core/client/v1/tx_pb.js';
import { ClientState, Header } from '../gen/ibc/lightclients/tendermint/v1/tendermint_pb.js';
import { DutchAuction } from '../gen/penumbra/core/component/auction/v1/auction_pb.js';

Expand Down Expand Up @@ -39,12 +36,6 @@ export const typeRegistry: IMessageTypeRegistry = createRegistry(
ClientState,
Header,

// gen/ibc/core/channel/v1/tx_pb
MsgRecvPacket,

// gen/ibc/core/client/v1/tx_pb
MsgUpdateClient,

// penumbra/core/component/auction/v1/auction_pb
DutchAuction,
);
Expand Down
5 changes: 4 additions & 1 deletion packages/protobuf/src/services/cosmos-ibc-core.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
export { Query as IbcChannelService } from '../../gen/ibc/core/channel/v1/query_connect.js';
export { Msg as IbcChannelMsgService } from '../../gen/ibc/core/channel/v1/tx_connect.js';

export { Query as IbcClientService } from '../../gen/ibc/core/client/v1/query_connect.js';
export { Msg as IbcClientMsgService } from '../../gen/ibc/core/client/v1/tx_connect.js';
export { Msg as IbcChannelMsgService } from '../../gen/ibc/core/channel/v1/tx_connect.js';

export { Query as IbcConnectionService } from '../../gen/ibc/core/connection/v1/query_connect.js';
export { Msg as IbcConnectionMsgService } from '../../gen/ibc/core/connection/v1/tx_connect.js';
2 changes: 2 additions & 0 deletions packages/protobuf/src/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
IbcChannelService,
IbcClientMsgService,
IbcClientService,
IbcConnectionMsgService,
IbcConnectionService,
} from './services/cosmos-ibc-core.js';
import type { CustodyService } from './services/penumbra-custody.js';
Expand Down Expand Up @@ -36,6 +37,7 @@ export type PenumbraService =
| typeof IbcClientService
| typeof IbcClientMsgService
| typeof IbcConnectionService
| typeof IbcConnectionMsgService
| typeof SctService
| typeof ShieldedPoolService
| typeof SimulationService
Expand Down
33 changes: 2 additions & 31 deletions packages/query/src/helpers/identify-txs.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import { describe, expect, test } from 'vitest';
import {
CommitmentSource,
Nullifier,
} from '@penumbra-zone/protobuf/penumbra/core/component/sct/v1/sct_pb';
import { Nullifier } from '@penumbra-zone/protobuf/penumbra/core/component/sct/v1/sct_pb';
import { StateCommitment } from '@penumbra-zone/protobuf/penumbra/crypto/tct/v1/tct_pb';
import {
Action,
Transaction,
TransactionBody,
} from '@penumbra-zone/protobuf/penumbra/core/transaction/v1/transaction_pb';
import {
BLANK_TX_SOURCE,
getCommitmentsFromActions,
getNullifiersFromActions,
identifyTransactions,
parseIntoAddr,
} from './identify-txs.js';
import {
Output,
Expand All @@ -38,10 +35,6 @@ import { Address } from '@penumbra-zone/protobuf/penumbra/core/keys/v1/keys_pb';
import { Packet } from '@penumbra-zone/protobuf/ibc/core/channel/v1/channel_pb';
import { MsgRecvPacket } from '@penumbra-zone/protobuf/ibc/core/channel/v1/tx_pb';

const BLANK_TX_SOURCE = new CommitmentSource({
source: { case: 'transaction', value: { id: new Uint8Array() } },
});

describe('getCommitmentsFromActions', () => {
test('returns empty array when tx.body.actions is undefined', () => {
const tx = new Transaction();
Expand Down Expand Up @@ -385,25 +378,3 @@ const createIbcRelay = (receiver: string): Action => {
action: { case: 'ibcRelayAction', value: new IbcRelay({ rawAction: relevantRelay }) },
});
};

describe('parseIntoAddr', () => {
test('works with compat', () => {
expect(() =>
parseIntoAddr(
'penumbracompat1147mfall0zr6am5r45qkwht7xqqrdsp50czde7empv7yq2nk3z8yyfh9k9520ddgswkmzar22vhz9dwtuem7uxw0qytfpv7lk3q9dp8ccaw2fn5c838rfackazmgf3ahhwqq0da',
),
).not.toThrow();
});

test('works with normal addresses', () => {
expect(() =>
parseIntoAddr(
'penumbra1e8k5cyds484dxvapeamwveh5khqv4jsvyvaf5wwxaaccgfghm229qw03pcar3ryy8smptevstycch0qk3uu0rgkvtjpxy3cu3rjd0agawqtlz6erev28a6sg69u7cxy0t02nd4',
),
).not.toThrow();
});

test('raises on invalid addresses', () => {
expect(() => parseIntoAddr('not_valid_format')).toThrow();
});
});
15 changes: 3 additions & 12 deletions packages/query/src/helpers/identify-txs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,16 @@ import { Transaction } from '@penumbra-zone/protobuf/penumbra/core/transaction/v
import { TransactionId } from '@penumbra-zone/protobuf/penumbra/core/txhash/v1/txhash_pb';
import { sha256Hash } from '@penumbra-zone/crypto-web/sha256';
import { MsgRecvPacket } from '@penumbra-zone/protobuf/ibc/core/channel/v1/tx_pb';
import { Address } from '@penumbra-zone/protobuf/penumbra/core/keys/v1/keys_pb';
import { FungibleTokenPacketData } from '@penumbra-zone/protobuf/penumbra/core/component/ibc/v1/ibc_pb';
import { addressFromBech32m } from '@penumbra-zone/bech32m/penumbra';
import { compatAddressFromBech32, isCompatAddress } from '@penumbra-zone/bech32m/penumbracompat1';
import { ViewServerInterface } from '@penumbra-zone/types/servers';
import { parseIntoAddr } from '@penumbra-zone/types/address';

const BLANK_TX_SOURCE = new CommitmentSource({
export const BLANK_TX_SOURCE = new CommitmentSource({
source: { case: 'transaction', value: { id: new Uint8Array() } },
});

export const parseIntoAddr = (addrStr: string): Address => {
if (isCompatAddress(addrStr)) {
return new Address(compatAddressFromBech32(addrStr));
}
return new Address(addressFromBech32m(addrStr));
};

// Identifies if a tx with a relay action of which the receiver is the user
export const hasRelevantIbcRelay = (
const hasRelevantIbcRelay = (
tx: Transaction,
isControlledAddr: ViewServerInterface['isControlledAddress'],
) => {
Expand Down
5 changes: 3 additions & 2 deletions packages/storage/src/indexed-db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ 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';
import { typeRegistry } from '@penumbra-zone/protobuf';

const assertBytes = (v?: Uint8Array, expect?: number, name = 'value'): v is Uint8Array => {
if (expect !== undefined && v?.length !== expect) {
Expand Down Expand Up @@ -363,7 +364,7 @@ export class IndexedDb implements IndexedDbInterface {
const tx = new TransactionInfo({ id, height, transaction });
await this.u.update({
table: 'TRANSACTIONS',
value: tx.toJson() as Jsonified<TransactionInfo>,
value: tx.toJson({ typeRegistry }) as Jsonified<TransactionInfo>,
});
}

Expand All @@ -374,7 +375,7 @@ export class IndexedDb implements IndexedDbInterface {
if (!jsonRecord) {
return undefined;
}
return TransactionInfo.fromJson(jsonRecord);
return TransactionInfo.fromJson(jsonRecord, { typeRegistry });
}

async getFmdParams(): Promise<FmdParameters | undefined> {
Expand Down
3 changes: 2 additions & 1 deletion packages/storage/src/indexed-db/stream.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AnyMessage, JsonValue, Message, MessageType } from '@bufbuild/protobuf';
import { IDBPCursorWithValue } from 'idb';
import type { PenumbraDb, PenumbraStoreNames } from '@penumbra-zone/types/indexed-db';
import { typeRegistry } from '@penumbra-zone/protobuf';

export class IdbCursorSource<N extends PenumbraStoreNames, T extends Message<T> = AnyMessage>
implements UnderlyingDefaultSource<T>
Expand All @@ -15,7 +16,7 @@ export class IdbCursorSource<N extends PenumbraStoreNames, T extends Message<T>
void (async () => {
let cursor = await this.cursor;
while (cursor) {
cont.enqueue(this.messageType.fromJson(cursor.value as JsonValue));
cont.enqueue(this.messageType.fromJson(cursor.value as JsonValue, { typeRegistry }));
cursor = await cursor.continue();
}
cont.close();
Expand Down
24 changes: 24 additions & 0 deletions packages/types/src/address.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { describe, expect, test } from 'vitest';
import { parseIntoAddr } from './address.js';

describe('parseIntoAddr', () => {
test('works with compat', () => {
expect(() =>
parseIntoAddr(
'penumbracompat1147mfall0zr6am5r45qkwht7xqqrdsp50czde7empv7yq2nk3z8yyfh9k9520ddgswkmzar22vhz9dwtuem7uxw0qytfpv7lk3q9dp8ccaw2fn5c838rfackazmgf3ahhwqq0da',
),
).not.toThrow();
});

test('works with normal addresses', () => {
expect(() =>
parseIntoAddr(
'penumbra1e8k5cyds484dxvapeamwveh5khqv4jsvyvaf5wwxaaccgfghm229qw03pcar3ryy8smptevstycch0qk3uu0rgkvtjpxy3cu3rjd0agawqtlz6erev28a6sg69u7cxy0t02nd4',
),
).not.toThrow();
});

test('raises on invalid addresses', () => {
expect(() => parseIntoAddr('not_valid_format')).toThrow();
});
});
10 changes: 10 additions & 0 deletions packages/types/src/address.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Address } from '@penumbra-zone/protobuf/penumbra/core/keys/v1/keys_pb';
import { addressFromBech32m } from '@penumbra-zone/bech32m/penumbra';
import { compatAddressFromBech32, isCompatAddress } from '@penumbra-zone/bech32m/penumbracompat1';

export const parseIntoAddr = (addrStr: string): Address => {
if (isCompatAddress(addrStr)) {
return new Address(compatAddressFromBech32(addrStr));
}
return new Address(addressFromBech32m(addrStr));
};
3 changes: 2 additions & 1 deletion packages/ui/components/ui/tx/action-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ValidatorVoteComponent } from './actions-views/validator-vote.tsx';
import { PositionOpenComponent } from './actions-views/position-open.tsx';
import { PositionCloseComponent } from './actions-views/position-close.tsx';
import { PositionWithdrawComponent } from './actions-views/position-withdraw.tsx';
import { IbcRelayComponent } from './actions-views/ibc-relay.tsx';

type Case = Exclude<ActionView['actionView']['case'], undefined>;

Expand Down Expand Up @@ -112,7 +113,7 @@ export const ActionViewComponent = ({
return <UnimplementedView label='Validator Definition' />;

case 'ibcRelayAction':
return <UnimplementedView label='IBC Relay Action' />;
return <IbcRelayComponent value={actionView.value} />;

case 'proposalSubmit':
return <UnimplementedView label='Proposal Submit' />;
Expand Down
141 changes: 141 additions & 0 deletions packages/ui/components/ui/tx/actions-views/ibc-relay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { ViewBox } from '../viewbox';
import { ActionDetails } from './action-details';
import {
FungibleTokenPacketData,
IbcRelay,
} from '@penumbra-zone/protobuf/penumbra/core/component/ibc/v1/ibc_pb';
import { MsgRecvPacket } from '@penumbra-zone/protobuf/ibc/core/channel/v1/tx_pb';
import { MsgUpdateClient } from '@penumbra-zone/protobuf/ibc/core/client/v1/tx_pb';
import { UnimplementedView } from './unimplemented-view.tsx';
import { uint8ArrayToBase64 } from '@penumbra-zone/types/base64';
import { getUtcTime } from './isc20-withdrawal.tsx';
import { useMemo } from 'react';

// Packet data stored as json string encoded into bytes
const parsePacket = ({ packet }: MsgRecvPacket): FungibleTokenPacketData | undefined => {
if (!packet?.data) {
return undefined;
}

try {
const dataString = new TextDecoder().decode(packet.data);
return FungibleTokenPacketData.fromJsonString(dataString);
} catch (e) {
return undefined;
}
};

const MsgResvComponent = ({ packet }: { packet: MsgRecvPacket }) => {
const packetData = useMemo(() => parsePacket(packet), [packet]);

return (
<ViewBox
label='IBC Relay: Msg Received'
visibleContent={
<ActionDetails>
{!!packetData?.sender && (
<ActionDetails.Row label='Sender'>
<ActionDetails.TruncatedText>{packetData.sender}</ActionDetails.TruncatedText>
</ActionDetails.Row>
)}
{!!packetData?.receiver && (
<ActionDetails.Row label='Receiver'>
<ActionDetails.TruncatedText>{packetData.receiver}</ActionDetails.TruncatedText>
</ActionDetails.Row>
)}
{!!packetData?.denom && (
<ActionDetails.Row label='Denom'>{packetData.denom}</ActionDetails.Row>
)}
{!!packetData?.amount && (
<ActionDetails.Row label='Amount'>{packetData.amount}</ActionDetails.Row>
)}
{packetData && 'memo' in packetData && (
<ActionDetails.Row label='Memo'>{packetData.memo}</ActionDetails.Row>
)}
{!!packet.packet?.sequence && (
<ActionDetails.Row label='Sequence'>{Number(packet.packet.sequence)}</ActionDetails.Row>
)}
{!!packet.packet?.sourcePort && (
<ActionDetails.Row label='Source Port'>{packet.packet.sourcePort}</ActionDetails.Row>
)}
{!!packet.packet?.sourceChannel && (
<ActionDetails.Row label='Source Channel'>
{packet.packet.sourceChannel}
</ActionDetails.Row>
)}
{!!packet.packet?.destinationPort && (
<ActionDetails.Row label='Destination Port'>
{packet.packet.destinationPort}
</ActionDetails.Row>
)}
{!!packet.packet?.destinationChannel && (
<ActionDetails.Row label='Destination Channel'>
{packet.packet.destinationChannel}
</ActionDetails.Row>
)}
{!!packet.packet?.timeoutHeight?.revisionHeight && (
<ActionDetails.Row label='Timeout revision height'>
{Number(packet.packet.timeoutHeight.revisionHeight)}
</ActionDetails.Row>
)}
{!!packet.packet?.timeoutHeight?.revisionNumber && (
<ActionDetails.Row label='Timeout revision number'>
{Number(packet.packet.timeoutHeight.revisionNumber)}
</ActionDetails.Row>
)}
{!!packet.packet?.timeoutTimestamp && (
<ActionDetails.Row label='Timeout timestamp'>
{getUtcTime(packet.packet.timeoutTimestamp)}
</ActionDetails.Row>
)}
<ActionDetails.Row label='Signer'>{packet.signer}</ActionDetails.Row>
{!!packet.proofHeight?.revisionHeight && (
<ActionDetails.Row label='Proof revision height'>
{Number(packet.proofHeight.revisionHeight)}
</ActionDetails.Row>
)}
{!!packet.proofHeight?.revisionNumber && (
<ActionDetails.Row label='Proof revision number'>
{Number(packet.proofHeight.revisionNumber)}
</ActionDetails.Row>
)}
<ActionDetails.Row label='Proof commitment'>
<ActionDetails.TruncatedText>
{uint8ArrayToBase64(packet.proofCommitment)}
</ActionDetails.TruncatedText>
</ActionDetails.Row>
</ActionDetails>
}
/>
);
};

const UpdateClientComponent = ({ update }: { update: MsgUpdateClient }) => {
return (
<ViewBox
label='IBC Relay: Update Client'
visibleContent={
<ActionDetails>
<ActionDetails.Row label='Client id'>{update.clientId}</ActionDetails.Row>
<ActionDetails.Row label='Signer'>{update.signer}</ActionDetails.Row>
</ActionDetails>
}
/>
);
};

export const IbcRelayComponent = ({ value }: { value: IbcRelay }) => {
if (value.rawAction?.is(MsgRecvPacket.typeName)) {
const packet = new MsgRecvPacket();
value.rawAction.unpackTo(packet);
return <MsgResvComponent packet={packet} />;
}

if (value.rawAction?.is(MsgUpdateClient.typeName)) {
const update = new MsgUpdateClient();
value.rawAction.unpackTo(update);
return <UpdateClientComponent update={update} />;
}

return <UnimplementedView label='IBC Relay' />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { ActionDetails } from './action-details';
import { joinLoHiAmount } from '@penumbra-zone/types/amount';
import { bech32mAddress } from '@penumbra-zone/bech32m/penumbra';

const getUtcTime = (time: bigint) => {
// Converts nanoseconds timestamp to UTC timestamp string
export const getUtcTime = (time: bigint) => {
const formatter = new Intl.DateTimeFormat('en-US', {
dateStyle: 'medium',
timeStyle: 'long',
Expand Down

0 comments on commit 8e9bc8c

Please sign in to comment.