Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LW-10737: Credential indexer #1

Merged
merged 1 commit into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compose/common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ services:
'--node-config',
'/config/cardano-node/config.json',
'--log-level-websocket',
'Warning'
'Warning',
'--include-cbor'
]
depends_on:
cardano-node:
Expand Down
45 changes: 13 additions & 32 deletions demo/projection-typeorm.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,14 @@ const {
withTypeormTransaction,
typeormTransactionCommit,
TypeormStabilityWindowBuffer,
BlockDataEntity,
BlockEntity,
StakePoolEntity,
PoolRegistrationEntity,
PoolRetirementEntity,
OutputEntity,
AssetEntity,
TokensEntity,
storeBlock,
storeAssets,
BlockEntity,
CredentialEntity,
TransactionEntity,
storeUtxo,
storeStakePools,
storeStakePoolMetadataJob,
storeBlock,
storeCredentials,
storeTransactions,
isRecoverableTypeormError
} = require('@cardano-sdk/projection-typeorm');
const { OgmiosObservableCardanoNode } = require('@cardano-sdk/ogmios');
Expand All @@ -32,14 +27,9 @@ const logger = {
};

const entities = [
BlockDataEntity,
BlockEntity,
StakePoolEntity,
PoolRegistrationEntity,
PoolRetirementEntity,
AssetEntity,
TokensEntity,
OutputEntity
CredentialEntity,
TransactionEntity,
];
const extensions = {
pgBoss: true
Expand Down Expand Up @@ -101,26 +91,17 @@ Bootstrap.fromCardanoNode({
logger
})
.pipe(
Mappers.withCertificates(),
Mappers.withStakePools(),
Mappers.withMint(),
Mappers.withUtxo(),
// Single-tenant example
// Mappers.filterProducedUtxoByAddresses({
// addresses: [
// 'addr_test1qpgn04xka0857kh6859za75tfvlrlu2lft0yc9z87598yjezw8yvpkv977yj5va20xmd9vw5fczfl3uu4expskz8adfqpydths'
// ]
// }),
Mappers.withAddresses(),
shareRetryBackoff(
(evt$) =>
evt$.pipe(
withTypeormTransaction({ dataSource$, logger }, extensions),
storeBlock(),
buffer.storeBlockData(),
storeAssets(),
storeUtxo(),
storeStakePools(),
storeStakePoolMetadataJob(),
storeBlock(),
storeCredentials(),
storeTransactions(),
// buffer.storeBlockData(),
typeormTransactionCommit()
),
{ shouldRetry: isRecoverableTypeormError }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
AssetEntity,
BlockDataEntity,
BlockEntity,
CredentialEntity,
CurrentPoolMetricsEntity,
DataSourceExtensions,
HandleEntity,
Expand All @@ -17,28 +18,33 @@ import {
StakeKeyRegistrationEntity,
StakePoolEntity,
TokensEntity,
TransactionEntity,
createStorePoolMetricsUpdateJob,
createStoreStakePoolMetadataJob,
storeAddresses,
storeAssets,
storeBlock,
storeCredentials,
storeHandleMetadata,
storeHandles,
storeNftMetadata,
storeStakeKeyRegistrations,
storeStakePoolRewardsJob,
storeStakePools,
storeTransactions,
storeUtxo,
willStoreAddresses,
willStoreAssets,
willStoreBlockData,
willStoreCredentials,
willStoreHandleMetadata,
willStoreHandles,
willStoreNftMetadata,
willStoreStakeKeyRegistrations,
willStoreStakePoolMetadataJob,
willStoreStakePoolRewardsJob,
willStoreStakePools,
willStoreTransactions,
willStoreUtxo
} from '@cardano-sdk/projection-typeorm';
import { Cardano, ChainSyncEventType } from '@cardano-sdk/core';
Expand All @@ -57,6 +63,7 @@ export enum ProjectionName {
StakePoolMetadataJob = 'stake-pool-metadata-job',
StakePoolMetricsJob = 'stake-pool-metrics-job',
StakePoolRewardsJob = 'stake-pool-rewards-job',
Transaction = 'transaction',
UTXO = 'utxo'
}

Expand Down Expand Up @@ -112,6 +119,7 @@ export const storeOperators = {
storeAddresses: storeAddresses(),
storeAssets: storeAssets(),
storeBlock: storeBlock(),
storeCredentials: storeCredentials(),
storeHandleMetadata: storeHandleMetadata(),
storeHandles: storeHandles(),
storeNftMetadata: storeNftMetadata(),
Expand All @@ -123,6 +131,7 @@ export const storeOperators = {
storeStakePoolMetadataJob: createStoreStakePoolMetadataJob()(),
storeStakePoolRewardsJob: storeStakePoolRewardsJob(),
storeStakePools: storeStakePools(),
storeTransactions: storeTransactions(),
storeUtxo: storeUtxo()
};
type StoreOperators = typeof storeOperators;
Expand All @@ -138,13 +147,15 @@ type WillStore = {
const willStore: Partial<WillStore> = {
storeAddresses: willStoreAddresses,
storeAssets: willStoreAssets,
storeCredentials: willStoreCredentials,
storeHandleMetadata: willStoreHandleMetadata,
storeHandles: willStoreHandles,
storeNftMetadata: willStoreNftMetadata,
storeStakeKeyRegistrations: willStoreStakeKeyRegistrations,
storeStakePoolMetadataJob: willStoreStakePoolMetadataJob,
storeStakePoolRewardsJob: willStoreStakePoolRewardsJob,
storeStakePools: willStoreStakePools,
storeTransactions: willStoreTransactions,
storeUtxo: willStoreUtxo
};

Expand All @@ -153,6 +164,7 @@ const entities = {
asset: AssetEntity,
block: BlockEntity,
blockData: BlockDataEntity,
credential: CredentialEntity,
currentPoolMetrics: CurrentPoolMetricsEntity,
handle: HandleEntity,
handleMetadata: HandleMetadataEntity,
Expand All @@ -165,7 +177,8 @@ const entities = {
poolRewards: PoolRewardsEntity,
stakeKeyRegistration: StakeKeyRegistrationEntity,
stakePool: StakePoolEntity,
tokens: TokensEntity
tokens: TokensEntity,
transaction: TransactionEntity
};
export const allEntities = Object.values(entities);
type Entities = typeof entities;
Expand All @@ -176,6 +189,7 @@ const storeEntities: Partial<Record<StoreName, EntityName[]>> = {
storeAddresses: ['address'],
storeAssets: ['asset'],
storeBlock: ['block', 'blockData'],
storeCredentials: ['credential', 'transaction', 'output'],
storeHandleMetadata: ['handleMetadata', 'output'],
storeHandles: ['handle', 'asset', 'tokens', 'output'],
storeNftMetadata: ['asset'],
Expand All @@ -186,13 +200,15 @@ const storeEntities: Partial<Record<StoreName, EntityName[]>> = {
storeStakePoolMetadataJob: ['stakePool', 'currentPoolMetrics', 'poolMetadata'],
storeStakePoolRewardsJob: ['poolRewards', 'stakePool'],
storeStakePools: ['stakePool', 'currentPoolMetrics', 'poolMetadata', 'poolDelisted'],
storeTransactions: ['block', 'transaction'],
storeUtxo: ['tokens', 'output']
};

const entityInterDependencies: Partial<Record<EntityName, EntityName[]>> = {
address: ['stakeKeyRegistration'],
asset: ['block', 'nftMetadata'],
blockData: ['block'],
credential: [],
currentPoolMetrics: ['stakePool'],
handle: ['asset'],
handleMetadata: ['output'],
Expand All @@ -203,7 +219,8 @@ const entityInterDependencies: Partial<Record<EntityName, EntityName[]>> = {
poolRetirement: ['block'],
stakeKeyRegistration: ['block'],
stakePool: ['block', 'poolRegistration', 'poolRetirement'],
tokens: ['asset']
tokens: ['asset'],
transaction: ['block', 'credential']
};

export const getEntities = (entityNames: EntityName[]): Entity[] => {
Expand Down Expand Up @@ -241,6 +258,7 @@ const mapperInterDependencies: Partial<Record<MapperName, MapperName[]>> = {
const storeMapperDependencies: Partial<Record<StoreName, MapperName[]>> = {
storeAddresses: ['withAddresses'],
storeAssets: ['withMint'],
storeCredentials: ['withAddresses', 'withCertificates', 'withUtxo'],
storeHandleMetadata: ['withHandleMetadata'],
storeHandles: ['withHandles'],
storeNftMetadata: ['withNftMetadata'],
Expand All @@ -260,6 +278,7 @@ const storeInterDependencies: Partial<Record<StoreName, StoreName[]>> = {
storeStakePoolMetadataJob: ['storeBlock'],
storeStakePoolRewardsJob: ['storeBlock'],
storeStakePools: ['storeBlock'],
storeTransactions: ['storeCredentials', 'storeBlock'],
storeUtxo: ['storeBlock', 'storeAssets']
};

Expand All @@ -273,6 +292,7 @@ const projectionStoreDependencies: Record<ProjectionName, StoreName[]> = {
'stake-pool-metadata-job': ['storeStakePoolMetadataJob'],
'stake-pool-metrics-job': ['storePoolMetricsUpdateJob'],
'stake-pool-rewards-job': ['storeStakePoolRewardsJob'],
transaction: ['storeCredentials', 'storeTransactions', 'storeUtxo'],
utxo: ['storeUtxo']
};

Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/Cardano/types/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ProposalProcedure, VotingProcedures } from './Governance';
import { RewardAccount } from '../Address';
import { Script } from './Script';
import { TxBodyCBOR } from '../../CBOR/TxBodyCBOR';
import { TxCBOR } from '../../CBOR';
import { bytesToHex, hexToBytes } from '../../util/misc';

/** transaction hash as hex string */
Expand Down Expand Up @@ -159,6 +160,7 @@ export interface OnChainTx<TBody extends TxBody = TxBody>
extends Omit<TxWithInputSource<TBody>, 'witness' | 'auxiliaryData'> {
witness: Omit<Witness, 'scripts'>;
auxiliaryData?: Omit<AuxiliaryData, 'scripts'>;
cbor?: TxCBOR;
}

export interface HydratedTx extends TxWithInputSource<HydratedTxBody> {
Expand Down
4 changes: 3 additions & 1 deletion packages/ogmios/src/ogmiosToCore/tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
NotImplementedError,
Serialization,
SerializationError,
SerializationFailure
SerializationFailure,
TxCBOR
} from '@cardano-sdk/core';
import { CommonBlock } from './types';
import { Schema } from '@cardano-ogmios/client';
Expand Down Expand Up @@ -432,6 +433,7 @@ const mapCommonTx = (tx: Schema.Transaction): Cardano.OnChainTx => {
withdrawals: mapWithdrawals(tx.withdrawals)
})
},
cbor: tx.cbor ? TxCBOR(tx.cbor) : undefined,
id: Cardano.TransactionId(tx.id),
// At the time of writing Byron transactions didn't set this property
inputSource: tx.spends ? Cardano.InputSource[tx.spends] : Cardano.InputSource.inputs,
Expand Down
26 changes: 26 additions & 0 deletions packages/projection-typeorm/src/entity/Credential.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Column, Entity, Index, ManyToMany, PrimaryColumn } from 'typeorm';
import { Hash28ByteBase16 } from '@cardano-sdk/crypto';
import { TransactionEntity } from './Transaction.entity';

export enum CredentialType {
PaymentKey = 'payment_key',
PaymentScript = 'payment_script',
StakeKey = 'stake_key',
StakeScript = 'stake_script'
}

@Entity()
export class CredentialEntity {
@Index()
@PrimaryColumn('varchar')
credentialHash?: Hash28ByteBase16;

@Column('enum', { enum: CredentialType, nullable: false })
credentialType?: CredentialType;

@ManyToMany(() => TransactionEntity, (transaction) => transaction.credentials, { onDelete: 'CASCADE' })
transactions?: TransactionEntity[];
}

export const credentialEntityComparator = (c1: CredentialEntity, c2: CredentialEntity) =>
c1.credentialHash === c2.credentialHash && c1.credentialType === c2.credentialType;
27 changes: 27 additions & 0 deletions packages/projection-typeorm/src/entity/Transaction.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { BlockEntity } from './Block.entity';
import { Cardano, TxCBOR } from '@cardano-sdk/core';
import { Column, Entity, Index, JoinColumn, JoinTable, ManyToMany, ManyToOne, PrimaryColumn } from 'typeorm';
import { CredentialEntity } from './Credential.entity';
import { OnDeleteCascadeRelationOptions } from './util';

@Entity()
export class TransactionEntity {
@Index()
@PrimaryColumn('varchar')
txId?: Cardano.TransactionId;

@Column('varchar', { nullable: false })
cbor?: TxCBOR;

@ManyToOne(() => BlockEntity, OnDeleteCascadeRelationOptions)
@JoinColumn({ name: 'block_id' })
block?: BlockEntity;

@ManyToMany(() => CredentialEntity, (credential) => credential.transactions, { onDelete: 'CASCADE' })
@JoinTable({
inverseJoinColumn: { name: 'credential_id', referencedColumnName: 'credentialHash' },
joinColumn: { name: 'transaction_id', referencedColumnName: 'txId' },
name: 'transaction_credentials'
})
credentials?: CredentialEntity[];
}
2 changes: 2 additions & 0 deletions packages/projection-typeorm/src/entity/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './Address.entity';
export * from './Asset.entity';
export * from './Block.entity';
export * from './BlockData.entity';
export * from './Credential.entity';
export * from './CurrentPoolMetrics.entity';
export * from './Handle.entity';
export * from './HandleMetadata.entity';
Expand All @@ -15,4 +16,5 @@ export * from './PoolRewards.entity';
export * from './StakeKey.entity';
export * from './StakeKeyRegistration.entity';
export * from './StakePool.entity';
export * from './Transaction.entity';
export * from './Tokens.entity';
2 changes: 2 additions & 0 deletions packages/projection-typeorm/src/operators/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './storeAddresses';
export * from './storeAssets';
export * from './storeBlock';
export * from './storeCredentials';
export * from './storeHandles';
export * from './storeHandleMetadata';
export * from './storeNftMetadata';
Expand All @@ -10,6 +11,7 @@ export * from './storeStakeKeyRegistrations';
export * from './storeStakePools';
export * from './storeStakePoolMetadataJob';
export * from './storeStakePoolRewardsJob';
export * from './storeTransactions';
export * from './storeUtxo';
export * from './util';
export * from './withTypeormTransaction';
Loading
Loading