Skip to content

Commit

Permalink
add endpoint get pool's delegation history by pool
Browse files Browse the repository at this point in the history
  • Loading branch information
ecioppettini committed Oct 12, 2023
1 parent d7a1078 commit b9ad7ab
Show file tree
Hide file tree
Showing 13 changed files with 306 additions and 24 deletions.
122 changes: 122 additions & 0 deletions docs/bin/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,69 @@
],
"type": "object"
},
"DelegationForPoolResponse": {
"items": {
"properties": {
"txId": {
"type": "string",
"nullable": true
},
"isDelegation": {
"type": "boolean"
},
"credential": {
"$ref": "#/components/schemas/Address"
}
},
"required": [
"txId",
"isDelegation",
"credential"
],
"type": "object"
},
"type": "array"
},
"PoolHex": {
"type": "string",
"example": "8200581c8baf48931c5187cd59fde553f4e7da2e1a2aa9202ec6e67815cb3f8a",
"pattern": "[0-9a-fA-F]{56}"
},
"Pool": {
"$ref": "#/components/schemas/PoolHex"
},
"DelegationForPoolRequest": {
"properties": {
"range": {
"properties": {
"maxSlot": {
"type": "number",
"format": "double"
},
"minSlot": {
"type": "number",
"format": "double"
}
},
"required": [
"maxSlot",
"minSlot"
],
"type": "object"
},
"pools": {
"items": {
"$ref": "#/components/schemas/Pool"
},
"type": "array"
}
},
"required": [
"range",
"pools"
],
"type": "object"
},
"PolicyId": {
"type": "string",
"example": "b863bc7369f46136ac1048adb2fa7dae3af944c3bbb2be2f216a8d4f",
Expand Down Expand Up @@ -1108,6 +1171,65 @@
}
}
},
"/delegation/pool": {
"post": {
"operationId": "DelegationForPool",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DelegationForPoolResponse"
}
}
}
},
"400": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorShape"
}
}
}
},
"409": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorShape"
}
}
}
},
"422": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorShape"
}
}
}
}
},
"security": [],
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DelegationForPoolRequest"
}
}
}
}
}
},
"/dex/last-price": {
"post": {
"operationId": "DexLastPrice",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Errors } from '../../../shared/errors';
import type { EndpointTypes } from '../../../shared/routes';
import { Routes } from '../../../shared/routes';
import { getAddressTypes } from '../models/utils';
import { delegationForAddress } from '../services/Delegation';
import { delegationForAddress } from '../services/DelegationForAddress';
import { DelegationForAddressResponse } from '../../../shared/models/DelegationForAddress';

const route = Routes.delegationForAddress;
Expand Down
47 changes: 47 additions & 0 deletions webserver/server/app/controllers/DelegationForPoolController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Body, Controller, TsoaResponse, Res, Post, Route, SuccessResponse } from 'tsoa';
import { StatusCodes } from 'http-status-codes';
import tx from 'pg-tx';
import pool from '../services/PgPoolSingleton';
import type { ErrorShape } from '../../../shared/errors';
import { genErrorMessage } from '../../../shared/errors';
import { Errors } from '../../../shared/errors';
import type { EndpointTypes } from '../../../shared/routes';
import { Routes } from '../../../shared/routes';
import { getAddressTypes } from '../models/utils';
import { delegationsForPool } from '../services/DelegationForPool';
import { DelegationForPoolResponse } from '../../../shared/models/DelegationForPool';

const route = Routes.delegationForPool;

@Route('delegation/pool')
export class DelegationForPoolController extends Controller {
@SuccessResponse(`${StatusCodes.OK}`)
@Post()
public async delegationForPool(
@Body()
requestBody: EndpointTypes[typeof route]['input'],
@Res()
errorResponse: TsoaResponse<
StatusCodes.BAD_REQUEST | StatusCodes.CONFLICT | StatusCodes.UNPROCESSABLE_ENTITY,
ErrorShape
>
): Promise<EndpointTypes[typeof route]['response']> {
const response = await tx<
DelegationForPoolResponse
>(pool, async dbTx => {
const data = await delegationsForPool({
pools: requestBody.pools.map(poolId => Buffer.from(poolId, 'hex')),
range: requestBody.range,
dbTx
});

return data.map(data => ({
credential: data.credential as string,
isDelegation: data.is_delegation as boolean,
txId: data.tx_id as string,
}));
});

return response;
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
/** Types generated for queries found in "app/models/delegation/delegationForAddress.sql" */
import { PreparedQuery } from '@pgtyped/query';

/** 'SqlStakeDelegation' parameters type */
export interface ISqlStakeDelegationParams {
/** 'SqlStakeDelegationForAddress' parameters type */
export interface ISqlStakeDelegationForAddressParams {
credential: Buffer;
slot: number;
}

/** 'SqlStakeDelegation' return type */
export interface ISqlStakeDelegationResult {
/** 'SqlStakeDelegationForAddress' return type */
export interface ISqlStakeDelegationForAddressResult {
pool: string | null;
tx_id: string | null;
}

/** 'SqlStakeDelegation' query type */
export interface ISqlStakeDelegationQuery {
params: ISqlStakeDelegationParams;
result: ISqlStakeDelegationResult;
/** 'SqlStakeDelegationForAddress' query type */
export interface ISqlStakeDelegationForAddressQuery {
params: ISqlStakeDelegationForAddressParams;
result: ISqlStakeDelegationForAddressResult;
}

const sqlStakeDelegationIR: any = {"usedParamSet":{"credential":true,"slot":true},"params":[{"name":"credential","required":true,"transform":{"type":"scalar"},"locs":[{"a":371,"b":382}]},{"name":"slot","required":true,"transform":{"type":"scalar"},"locs":[{"a":405,"b":410}]}],"statement":"SELECT encode(pool_credential, 'hex') as pool, encode(\"Transaction\".hash, 'hex') as tx_id\nFROM \"StakeDelegationCredentialRelation\"\nJOIN \"StakeCredential\" ON stake_credential = \"StakeCredential\".id\nJOIN \"Transaction\" ON \"Transaction\".id = \"StakeDelegationCredentialRelation\".tx_id\nJOIN \"Block\" ON \"Transaction\".block_id = \"Block\".id\nWHERE \n\t\"StakeCredential\".credential = :credential! AND\n\t\"Block\".slot <= :slot!\nORDER BY (\"Block\".height, \"Transaction\".tx_index) DESC\nLIMIT 1"};
const sqlStakeDelegationForAddressIR: any = {"usedParamSet":{"credential":true,"slot":true},"params":[{"name":"credential","required":true,"transform":{"type":"scalar"},"locs":[{"a":371,"b":382}]},{"name":"slot","required":true,"transform":{"type":"scalar"},"locs":[{"a":405,"b":410}]}],"statement":"SELECT encode(pool_credential, 'hex') as pool, encode(\"Transaction\".hash, 'hex') as tx_id\nFROM \"StakeDelegationCredentialRelation\"\nJOIN \"StakeCredential\" ON stake_credential = \"StakeCredential\".id\nJOIN \"Transaction\" ON \"Transaction\".id = \"StakeDelegationCredentialRelation\".tx_id\nJOIN \"Block\" ON \"Transaction\".block_id = \"Block\".id\nWHERE \n\t\"StakeCredential\".credential = :credential! AND\n\t\"Block\".slot <= :slot!\nORDER BY (\"Block\".height, \"Transaction\".tx_index) DESC\nLIMIT 1"};

/**
* Query generated from SQL:
Expand All @@ -36,6 +36,6 @@ const sqlStakeDelegationIR: any = {"usedParamSet":{"credential":true,"slot":true
* LIMIT 1
* ```
*/
export const sqlStakeDelegation = new PreparedQuery<ISqlStakeDelegationParams,ISqlStakeDelegationResult>(sqlStakeDelegationIR);
export const sqlStakeDelegationForAddress = new PreparedQuery<ISqlStakeDelegationForAddressParams,ISqlStakeDelegationForAddressResult>(sqlStakeDelegationForAddressIR);


Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* @name sqlStakeDelegation */
/* @name sqlStakeDelegationForAddress */
SELECT encode(pool_credential, 'hex') as pool, encode("Transaction".hash, 'hex') as tx_id
FROM "StakeDelegationCredentialRelation"
JOIN "StakeCredential" ON stake_credential = "StakeCredential".id
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/** Types generated for queries found in "app/models/delegation/delegationsForPool.sql" */
import { PreparedQuery } from '@pgtyped/query';

/** 'SqlStakeDelegationByPool' parameters type */
export interface ISqlStakeDelegationByPoolParams {
max_slot: number;
min_slot: number;
pools: readonly (Buffer)[];
}

/** 'SqlStakeDelegationByPool' return type */
export interface ISqlStakeDelegationByPoolResult {
credential: string | null;
is_delegation: boolean | null;
tx_id: string | null;
}

/** 'SqlStakeDelegationByPool' query type */
export interface ISqlStakeDelegationByPoolQuery {
params: ISqlStakeDelegationByPoolParams;
result: ISqlStakeDelegationByPoolResult;
}

const sqlStakeDelegationByPoolIR: any = {"usedParamSet":{"pools":true,"min_slot":true,"max_slot":true},"params":[{"name":"pools","required":true,"transform":{"type":"array_spread"},"locs":[{"a":160,"b":166},{"a":505,"b":511},{"a":572,"b":578}]},{"name":"min_slot","required":true,"transform":{"type":"scalar"},"locs":[{"a":603,"b":612}]},{"name":"max_slot","required":true,"transform":{"type":"scalar"},"locs":[{"a":635,"b":644}]}],"statement":"SELECT \n\tencode(credential, 'hex') as credential,\n\tencode(\"Transaction\".hash, 'hex') as tx_id,\n\tCOALESCE(\"StakeDelegationCredentialRelation\".pool_credential IN :pools!, false) as is_delegation\nFROM \"StakeDelegationCredentialRelation\"\nJOIN \"StakeCredential\" ON stake_credential = \"StakeCredential\".id\nJOIN \"Transaction\" ON \"Transaction\".id = \"StakeDelegationCredentialRelation\".tx_id\nJOIN \"Block\" ON \"Transaction\".block_id = \"Block\".id\nWHERE \n (\n\t\t\"StakeDelegationCredentialRelation\".pool_credential IN :pools! OR\n\t \t\"StakeDelegationCredentialRelation\".previous_pool IN :pools!\n\t) AND\n\t\"Block\".slot > :min_slot! AND\n\t\"Block\".slot <= :max_slot!\nORDER BY (\"Block\".height, \"Transaction\".tx_index) ASC"};

/**
* Query generated from SQL:
* ```
* SELECT
* encode(credential, 'hex') as credential,
* encode("Transaction".hash, 'hex') as tx_id,
* COALESCE("StakeDelegationCredentialRelation".pool_credential IN :pools!, false) as is_delegation
* FROM "StakeDelegationCredentialRelation"
* JOIN "StakeCredential" ON stake_credential = "StakeCredential".id
* JOIN "Transaction" ON "Transaction".id = "StakeDelegationCredentialRelation".tx_id
* JOIN "Block" ON "Transaction".block_id = "Block".id
* WHERE
* (
* "StakeDelegationCredentialRelation".pool_credential IN :pools! OR
* "StakeDelegationCredentialRelation".previous_pool IN :pools!
* ) AND
* "Block".slot > :min_slot! AND
* "Block".slot <= :max_slot!
* ORDER BY ("Block".height, "Transaction".tx_index) ASC
* ```
*/
export const sqlStakeDelegationByPool = new PreparedQuery<ISqlStakeDelegationByPoolParams,ISqlStakeDelegationByPoolResult>(sqlStakeDelegationByPoolIR);


20 changes: 20 additions & 0 deletions webserver/server/app/models/delegation/delegationsForPool.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
@name sqlStakeDelegationByPool
@param pools -> (...)
*/
SELECT
encode(credential, 'hex') as credential,
encode("Transaction".hash, 'hex') as tx_id,
COALESCE("StakeDelegationCredentialRelation".pool_credential IN :pools!, false) as is_delegation
FROM "StakeDelegationCredentialRelation"
JOIN "StakeCredential" ON stake_credential = "StakeCredential".id
JOIN "Transaction" ON "Transaction".id = "StakeDelegationCredentialRelation".tx_id
JOIN "Block" ON "Transaction".block_id = "Block".id
WHERE
(
"StakeDelegationCredentialRelation".pool_credential IN :pools! OR
"StakeDelegationCredentialRelation".previous_pool IN :pools!
) AND
"Block".slot > :min_slot! AND
"Block".slot <= :max_slot!
ORDER BY ("Block".height, "Transaction".tx_index) ASC;
12 changes: 0 additions & 12 deletions webserver/server/app/services/Delegation.ts

This file was deleted.

10 changes: 10 additions & 0 deletions webserver/server/app/services/DelegationForAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { PoolClient } from 'pg';
import { ISqlStakeDelegationForAddressResult, sqlStakeDelegationForAddress } from '../models/delegation/delegationForAddress.queries';

export async function delegationForAddress(request: {
address: Buffer,
until: { absoluteSlot: number },
dbTx: PoolClient,
}): Promise<ISqlStakeDelegationForAddressResult> {
return (await sqlStakeDelegationForAddress.run({ credential: request.address, slot: request.until.absoluteSlot }, request.dbTx))[0];
}
15 changes: 15 additions & 0 deletions webserver/server/app/services/DelegationForPool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { PoolClient } from 'pg';
import { ISqlStakeDelegationByPoolResult, sqlStakeDelegationByPool } from '../models/delegation/delegationsForPool.queries';


export async function delegationsForPool(request: {
range: { minSlot: number, maxSlot: number },
pools: Buffer[],
dbTx: PoolClient,
}): Promise<ISqlStakeDelegationByPoolResult[]> {
return (await sqlStakeDelegationByPool.run({
min_slot: request.range.minSlot,
max_slot: request.range.maxSlot,
pools: request.pools
}, request.dbTx));
}
13 changes: 13 additions & 0 deletions webserver/shared/models/DelegationForPool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Address } from "./Address";
import { Pool } from "./Pool";

export type DelegationForPoolRequest = {
pools: Pool[];
range: { minSlot: number, maxSlot: number }
};

export type DelegationForPoolResponse = {
credential: Address;
isDelegation: boolean,
txId: string | null;
}[];
8 changes: 8 additions & 0 deletions webserver/shared/models/Pool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @pattern [0-9a-fA-F]{56}
* @example "8200581c8baf48931c5187cd59fde553f4e7da2e1a2aa9202ec6e67815cb3f8a"
*/
export type PoolHex = string;

export type Pool =
| PoolHex
Loading

0 comments on commit b9ad7ab

Please sign in to comment.