Fixes for Solana value encoding and searches (#140)

Tested with a new test Hasura instance
pull/142/head
J M Rossy 2 weeks ago committed by GitHub
parent b7e8e1dcd3
commit d7da83d3a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      src/features/messages/pi-queries/usePiChainMessageQuery.ts
  2. 4
      src/features/messages/queries/build.ts
  3. 38
      src/features/messages/queries/encoding.ts
  4. 6
      src/features/messages/queries/parse.ts
  5. 17
      src/features/messages/queries/useMessageQuery.ts
  6. 2
      src/utils/string.ts

@ -46,7 +46,7 @@ export function usePiChainMessageSearchQuery({
], ],
queryFn: async () => { queryFn: async () => {
const hasInput = !!sanitizedInput; const hasInput = !!sanitizedInput;
const isValidInput = isValidSearchQuery(sanitizedInput, true); const isValidInput = isValidSearchQuery(sanitizedInput);
if (pause || !multiProvider || !hasInput || !isValidInput) return []; if (pause || !multiProvider || !hasInput || !isValidInput) return [];
logger.debug('Starting PI Chain message search for:', sanitizedInput); logger.debug('Starting PI Chain message search for:', sanitizedInput);
// TODO handle time-based filters here // TODO handle time-based filters here

@ -71,14 +71,12 @@ export function buildMessageSearchQuery(
limit: number, limit: number,
useStub = false, useStub = false,
) { ) {
const hasInput = !!searchInput;
const originChains = originFilter ? originFilter.split(',') : undefined; const originChains = originFilter ? originFilter.split(',') : undefined;
const destinationChains = destFilter ? destFilter.split(',') : undefined; const destinationChains = destFilter ? destFilter.split(',') : undefined;
const startTime = startTimeFilter ? adjustToUtcTime(startTimeFilter) : undefined; const startTime = startTimeFilter ? adjustToUtcTime(startTimeFilter) : undefined;
const endTime = endTimeFilter ? adjustToUtcTime(endTimeFilter) : undefined; const endTime = endTimeFilter ? adjustToUtcTime(endTimeFilter) : undefined;
const variables = { const variables = {
search: hasInput ? searchValueToPostgresBytea(searchInput) : undefined, search: searchValueToPostgresBytea(searchInput),
originChains, originChains,
destinationChains, destinationChains,
startTime, startTime,

@ -1,10 +1,16 @@
import { ChainMetadata } from '@hyperlane-xyz/sdk'; import { ChainMetadata } from '@hyperlane-xyz/sdk';
import { import {
addressToByteHexString, addressToByteHexString,
base58ToBuffer,
bufferToBase58,
bytesToProtocolAddress, bytesToProtocolAddress,
ensure0x, ensure0x,
isAddress, isAddress,
isAddressEvm, isAddressEvm,
isValidTransactionHashCosmos,
isValidTransactionHashEvm,
isValidTransactionHashSealevel,
ProtocolType,
strip0x, strip0x,
} from '@hyperlane-xyz/utils'; } from '@hyperlane-xyz/utils';
@ -34,7 +40,33 @@ export function postgresByteaToAddress(
return bytesToProtocolAddress(addressBytes, chainMetadata.protocol, chainMetadata.bech32Prefix); return bytesToProtocolAddress(addressBytes, chainMetadata.protocol, chainMetadata.bech32Prefix);
} }
export function searchValueToPostgresBytea(input: string): string { export function postgresByteaToTxHash(
if (isAddress(input)) return addressToPostgresBytea(input); byteString: string,
else return stringToPostgresBytea(input); chainMetadata: ChainMetadata | null | undefined,
): string {
const hexString = postgresByteaToString(byteString);
// Return hex string for protocols other than Sealevel
if (chainMetadata?.protocol !== ProtocolType.Sealevel) return hexString;
const bytes = Buffer.from(strip0x(hexString), 'hex');
return bufferToBase58(bytes);
}
export function searchValueToPostgresBytea(input: string): string | undefined {
if (!input) return undefined;
try {
if (isAddress(input)) {
return addressToPostgresBytea(input);
}
if (isValidTransactionHashEvm(input) || isValidTransactionHashCosmos(input)) {
return stringToPostgresBytea(input);
}
if (isValidTransactionHashSealevel(input)) {
const bytes = base58ToBuffer(input);
return stringToPostgresBytea(bytes.toString('hex'));
}
return undefined;
} catch (error) {
// Search input couldn't be decoded and recoded properly
return undefined;
}
} }

@ -6,7 +6,7 @@ import { tryUtf8DecodeBytes } from '../../../utils/string';
import { DomainsEntry } from '../../chains/queries/fragments'; import { DomainsEntry } from '../../chains/queries/fragments';
import { isPiChain } from '../../chains/utils'; import { isPiChain } from '../../chains/utils';
import { postgresByteaToAddress, postgresByteaToString } from './encoding'; import { postgresByteaToAddress, postgresByteaToString, postgresByteaToTxHash } from './encoding';
import { import {
MessageEntry, MessageEntry,
MessageStubEntry, MessageStubEntry,
@ -79,13 +79,13 @@ function parseMessageStub(
destinationDomainId: m.destination_domain_id, destinationDomainId: m.destination_domain_id,
origin: { origin: {
timestamp: parseTimestampString(m.send_occurred_at), timestamp: parseTimestampString(m.send_occurred_at),
hash: postgresByteaToString(m.origin_tx_hash), hash: postgresByteaToTxHash(m.origin_tx_hash, originMetadata),
from: postgresByteaToAddress(m.origin_tx_sender, originMetadata), from: postgresByteaToAddress(m.origin_tx_sender, originMetadata),
}, },
destination: m.is_delivered destination: m.is_delivered
? { ? {
timestamp: parseTimestampString(m.delivery_occurred_at!), timestamp: parseTimestampString(m.delivery_occurred_at!),
hash: postgresByteaToString(m.destination_tx_hash!), hash: postgresByteaToTxHash(m.destination_tx_hash!, destinationMetadata),
from: postgresByteaToAddress(m.destination_tx_sender!, destinationMetadata), from: postgresByteaToAddress(m.destination_tx_sender!, destinationMetadata),
} }
: undefined, : undefined,

@ -1,18 +1,13 @@
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useQuery } from 'urql'; import { useQuery } from 'urql';
import {
isAddress,
isValidTransactionHashCosmos,
isValidTransactionHashEvm,
} from '@hyperlane-xyz/utils';
import { useMultiProvider } from '../../../store'; import { useMultiProvider } from '../../../store';
import { MessageStatus } from '../../../types'; import { MessageStatus } from '../../../types';
import { useInterval } from '../../../utils/useInterval'; import { useInterval } from '../../../utils/useInterval';
import { useScrapedDomains } from '../../chains/queries/useScrapedChains'; import { useScrapedDomains } from '../../chains/queries/useScrapedChains';
import { MessageIdentifierType, buildMessageQuery, buildMessageSearchQuery } from './build'; import { MessageIdentifierType, buildMessageQuery, buildMessageSearchQuery } from './build';
import { searchValueToPostgresBytea } from './encoding';
import { MessagesQueryResult, MessagesStubQueryResult } from './fragments'; import { MessagesQueryResult, MessagesStubQueryResult } from './fragments';
import { parseMessageQueryResult, parseMessageStubResult } from './parse'; import { parseMessageQueryResult, parseMessageStubResult } from './parse';
@ -21,13 +16,9 @@ const MSG_AUTO_REFRESH_DELAY = 10_000; // 10s
const LATEST_QUERY_LIMIT = 100; const LATEST_QUERY_LIMIT = 100;
const SEARCH_QUERY_LIMIT = 50; const SEARCH_QUERY_LIMIT = 50;
export function isValidSearchQuery(input: string, allowAddress?: boolean) { export function isValidSearchQuery(input: string) {
if (!input) return false; if (!input) return false;
return !!( return !!searchValueToPostgresBytea(input);
isValidTransactionHashEvm(input) ||
isValidTransactionHashCosmos(input) ||
(allowAddress && isAddress(input))
);
} }
export function useMessageSearchQuery( export function useMessageSearchQuery(
@ -40,7 +31,7 @@ export function useMessageSearchQuery(
const { scrapedDomains: scrapedChains } = useScrapedDomains(); const { scrapedDomains: scrapedChains } = useScrapedDomains();
const hasInput = !!sanitizedInput; const hasInput = !!sanitizedInput;
const isValidInput = hasInput ? isValidSearchQuery(sanitizedInput, true) : true; const isValidInput = !hasInput || isValidSearchQuery(sanitizedInput);
// Assemble GraphQL query // Assemble GraphQL query
const { query, variables } = buildMessageSearchQuery( const { query, variables } = buildMessageSearchQuery(

@ -5,7 +5,7 @@ import { strip0x } from '@hyperlane-xyz/utils';
const alphanumericRgex = /[^a-zA-Z0-9]/gi; const alphanumericRgex = /[^a-zA-Z0-9]/gi;
export function sanitizeString(str: string) { export function sanitizeString(str: string) {
if (!str || typeof str !== 'string') return ''; if (!str || typeof str !== 'string') return '';
return str.replaceAll(alphanumericRgex, '').toLowerCase(); return str.replaceAll(alphanumericRgex, '');
} }
export function tryUtf8DecodeBytes(value: string, fatal = true) { export function tryUtf8DecodeBytes(value: string, fatal = true) {

Loading…
Cancel
Save