Skip to content

Commit

Permalink
feat: Interpolate blockTime for older solana blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
amalcaraz committed Oct 1, 2024
1 parent 624028e commit d16e4ec
Show file tree
Hide file tree
Showing 9 changed files with 306 additions and 249 deletions.
329 changes: 99 additions & 230 deletions packages/solana/src/sdk/client.ts

Large diffs are not rendered by default.

188 changes: 188 additions & 0 deletions packages/solana/src/sdk/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import {
type as pick,
number,
string,
array,
boolean,
literal,
union,
optional,
nullable,
coerce,
unknown,
tuple,
} from 'superstruct'

const AddressTableLookupStruct = pick({
accountKey: string(),
writableIndexes: array(number()),
readonlyIndexes: array(number()),
})

const LoadedAddressesResult = pick({
writable: array(string()),
readonly: array(string()),
})

const TokenAmountResult = pick({
amount: string(),
uiAmount: nullable(number()),
decimals: number(),
uiAmountString: optional(string()),
})

const TokenBalanceResult = pick({
accountIndex: number(),
mint: string(),
owner: optional(string()),
uiTokenAmount: TokenAmountResult,
})

const TransactionErrorResult = nullable(union([pick({}), string()]))

const RawInstructionResult = pick({
accounts: array(string()),
data: string(),
programId: string(),
})

const ParsedInstructionResult = pick({
parsed: unknown(),
program: string(),
programId: string(),
})

const InstructionResult = union([RawInstructionResult, ParsedInstructionResult])

const UnknownInstructionResult = union([
pick({
parsed: unknown(),
program: string(),
programId: string(),
}),
pick({
accounts: array(string()),
data: string(),
programId: string(),
}),
])

const ParsedOrRawInstruction = coerce(
InstructionResult,
UnknownInstructionResult,
(value) => {
if ('accounts' in value) {
RawInstructionResult
} else {
ParsedInstructionResult
}
},
)

const ParsedConfirmedTransactionResult = pick({
signatures: array(string()),
message: pick({
accountKeys: array(
pick({
pubkey: string(),
signer: boolean(),
writable: boolean(),
source: optional(
union([literal('transaction'), literal('lookupTable')]),
),
}),
),
instructions: array(ParsedOrRawInstruction),
recentBlockhash: string(),
addressTableLookups: optional(nullable(array(AddressTableLookupStruct))),
}),
})

const TransactionVersionStruct = union([literal(0), literal('legacy')])

const ParsedConfirmedTransactionMetaResult = pick({
err: TransactionErrorResult,
fee: number(),
innerInstructions: optional(
nullable(
array(
pick({
index: number(),
instructions: array(ParsedOrRawInstruction),
}),
),
),
),
preBalances: array(number()),
postBalances: array(number()),
logMessages: optional(nullable(array(string()))),
preTokenBalances: optional(nullable(array(TokenBalanceResult))),
postTokenBalances: optional(nullable(array(TokenBalanceResult))),
loadedAddresses: optional(LoadedAddressesResult),
computeUnitsConsumed: optional(number()),
})

const VoteAccountInfoResult = pick({
votePubkey: string(),
nodePubkey: string(),
activatedStake: number(),
epochVoteAccount: boolean(),
epochCredits: array(tuple([number(), number(), number()])),
commission: number(),
lastVote: number(),
rootSlot: nullable(number()),
})

const SupplyContext = pick({
apiVersion: string(),
slot: number(),
})

const SupplyValue = pick({
total: number(),
circulating: number(),
nonCirculating: number(),
nonCirculatingAccounts: array(string()),
})

/**
* Expected JSON RPC response for the "getSupply" message
*/
export const GetSupplyRpcResult = pick({
context: SupplyContext,
value: SupplyValue,
})

/**
* Expected JSON RPC response for the "getSignaturesForAddress" message
*/
export const GetSignaturesForAddressRpcResult = array(
pick({
signature: string(),
slot: number(),
err: TransactionErrorResult,
memo: nullable(string()),
blockTime: optional(nullable(number())),
}),
)

/**
* Expected JSON RPC response for the "getTransaction" message
*/
export const GetParsedTransactionRpcResult = nullable(
pick({
slot: number(),
transaction: ParsedConfirmedTransactionResult,
meta: nullable(ParsedConfirmedTransactionMetaResult),
blockTime: optional(nullable(number())),
version: optional(TransactionVersionStruct),
}),
)

/**
* Expected JSON RPC response for the "getVoteAccounts" message
*/
export const GetVoteAccounts = pick({
current: array(VoteAccountInfoResult),
delinquent: array(VoteAccountInfoResult),
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Duration } from 'luxon'
import { ConfirmedSignatureInfo } from '@solana/web3.js'
import { Utils } from '@aleph-indexer/core'
import {
BaseFetcherPaginationCursors,
Expand All @@ -13,6 +12,7 @@ import { SolanaAccountTransactionHistoryStorage } from './dal/accountTransaction
import {
SolanaAccountTransactionHistoryPaginationCursor,
SolanaSignature,
SolanaSignatureInfo,
} from './types.js'
import {
SolanaErrorFetching,
Expand Down Expand Up @@ -247,7 +247,7 @@ export class SolanaAccountTransactionHistoryFetcher extends BaseHistoryFetcher<S
}

protected async processSignatures(
signatures: ConfirmedSignatureInfo[],
signatures: SolanaSignatureInfo[],
goingForward: boolean,
runOffset: number,
sigOffset: number,
Expand All @@ -267,15 +267,9 @@ export class SolanaAccountTransactionHistoryFetcher extends BaseHistoryFetcher<S
const sigs = signatures.map((signature, index) => {
const offset = runOffset * 1000000 + (999999 - (index + sigOffset))

const sig = signature as any
sig.id = sig.signature

delete sig.memo
delete sig.confirmationStatus

const sig = signature as SolanaSignature
sig.accountSlotIndex = sig.accountSlotIndex || {}
sig.accountSlotIndex[this.account] = offset

sig.accounts = Object.keys(sig.accountSlotIndex)

return sig
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const accountKey = {
}

const timestampKey = {
get: (e: SolanaSignature) => (e.blockTime || 0) * 1000,
get: (e: SolanaSignature) => e.timestamp,
length: EntityStorage.TimestampLength,
}

Expand Down
8 changes: 5 additions & 3 deletions packages/solana/src/services/fetcher/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ export type SolanaAccountTransactionHistoryPaginationCursor = {
timestamp?: number
}

export type SolanaSignatureInfo = ConfirmedSignatureInfo

export type SolanaSignature = Omit<
export type SolanaSignatureInfo = Omit<
ConfirmedSignatureInfo,
'memo' | 'confirmationStatus'
> & {
id: string
signature: string
timestamp: number
}

export type SolanaSignature = SolanaSignatureInfo & {
accountSlotIndex: Record<string, number>
accounts: string[]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class SolanaIndexerTransactionFetcher extends BaseIndexerEntityFetcher<So
continue
}

const timestamp = (tx.blockTime || 0) * 1000
const timestamp = tx.timestamp

let valid = timestamp >= startDate && timestamp <= endDate

Expand Down
4 changes: 1 addition & 3 deletions packages/solana/src/services/parser/src/event/eventParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ export abstract class EventParser<
: ''
}:${instruction.index.toString().padStart(2, '0')}`

const timestamp = parentTransaction.blockTime
? parentTransaction.blockTime * 1000
: parentTransaction.slot
const timestamp = parentTransaction.timestamp

return {
...parsed.info,
Expand Down
8 changes: 6 additions & 2 deletions packages/solana/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,11 @@ export type SolanaRawTransactionOld = ConfirmedSignatureInfo &
/**
* Expected JSON RPC response for the "getTransaction" message
*/
export type SolanaRawTransaction = RawEntity & RawParsedTransactionWithMeta
export type SolanaRawTransaction = RawEntity &
RawParsedTransactionWithMeta & {
signature: string
timestamp: number
}

export type RawAccountInfo = AccountInfo<Buffer>

Expand Down Expand Up @@ -223,7 +227,7 @@ export type SolanaParsedTransaction = Omit<
parsed: AlephParsedInnerTransaction
index: number
signature: string
blocktime: number
blockTime?: number
slot: number
}

Expand Down
2 changes: 2 additions & 0 deletions packages/solana/src/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,13 @@ export const TransactionError = new GraphQLObjectType({
export const TransactionItem = new GraphQLObjectType({
name: 'TransactionItem',
fields: {
id: { type: new GraphQLNonNull(GraphQLString) },
signature: { type: new GraphQLNonNull(GraphQLString) },
slot: { type: new GraphQLNonNull(GraphQLInt) },
err: { type: TransactionError },
memo: { type: GraphQLString },
blockTime: { type: GraphQLLong },
timestamp: { type: GraphQLLong },
parsed: { type: ParsedTransactionType },
meta: { type: ParsedConfirmedTransactionMeta },
},
Expand Down

0 comments on commit d16e4ec

Please sign in to comment.