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

Improved Filtering and Selection Logic for Best Tip and Tie Breaker Mechanism #80

Merged
merged 73 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
44cc705
WIP
MartinMinkov Apr 10, 2023
56860c9
feat: Fix events from multiple transactions
MartinMinkov Apr 11, 2023
1e6a797
feat: Refactor actions in the same way as events
MartinMinkov Apr 12, 2023
4a77162
feat: Add sorting methods
MartinMinkov Apr 13, 2023
c27a83d
chore: Move functions
MartinMinkov Apr 13, 2023
f6dba13
feat: Add new fields to query
MartinMinkov Apr 17, 2023
098d2eb
wip
MartinMinkov Apr 20, 2023
11e6214
Merge branch 'main' into feat/selection-algo
MartinMinkov Apr 24, 2023
59b2c27
Implement chain selection
MartinMinkov Apr 24, 2023
d35b10c
Remove unneeded types
MartinMinkov Apr 24, 2023
aad0f1b
Refactor for readability
MartinMinkov Apr 25, 2023
bfaf506
refactor(archive-node-adapter): remove select function from archive-n…
MartinMinkov Jul 27, 2023
8d9c930
feat(mina-consensus.ts): add new file to handle Mina Protocol's conse…
MartinMinkov Jul 27, 2023
02b316c
feat(archive-node-adapter): refactor events and actions into services
MartinMinkov Jul 27, 2023
34a028f
Merge branch 'main' into feat/selection-algo
MartinMinkov Jul 27, 2023
502a284
refactor: change import paths from absolute to relative for better co…
MartinMinkov Jul 27, 2023
b6effc0
feat(package.json): add typescript as a devDependency to enable TypeS…
MartinMinkov Jul 27, 2023
8c364a8
feat(Dockerfile): upgrade base image from node:14 to node:18-alpine f…
MartinMinkov Jul 27, 2023
8415204
feat: add docker-compose.dev.yml for development environment setup
MartinMinkov Jul 27, 2023
20fc77c
feat(consensus): implement first iteration of mina pos
MartinMinkov Jul 27, 2023
4362df2
refactor(mina-consensus.ts): remove unused compareHash function and c…
MartinMinkov Jul 28, 2023
3755fc0
feat(consensus): add precomputed-block.ts and run-consensus-precomput…
MartinMinkov Jul 28, 2023
d7dc9ff
feat(run-consensus-precomputed.ts): add block data output to JSON fil…
MartinMinkov Jul 28, 2023
0fcab2e
feat(run-consensus-precomputed.ts, types.ts): refactor block structur…
MartinMinkov Jul 28, 2023
45a5cc5
feat(run-compare.ts): add new file to compare TypeScript and OCaml files
MartinMinkov Jul 28, 2023
6294d0c
docs(run-compare.ts): add usage comment at the top of the file to gui…
MartinMinkov Jul 31, 2023
34131fc
feat(consensus): add run-compare.ts and run-consensus-precomputed.ts …
MartinMinkov Jul 31, 2023
c951879
feat(run-compare.ts): add environment variables for TypeScript and OC…
MartinMinkov Jul 31, 2023
3ce60ac
feat(scripts): add download_precomputed.sh script to download and fil…
MartinMinkov Jul 31, 2023
ba52030
refactor(archive-node-adapter/utils.ts): extract unique event id crea…
MartinMinkov Aug 14, 2023
ab79ef6
refactor(mina-consensus.ts, utils.ts): move findAllIndexes function f…
MartinMinkov Aug 14, 2023
e3ce297
refactor(actions-service.ts, events-service.ts): simplify async funct…
MartinMinkov Aug 14, 2023
d8ed0b4
refactor(types.ts): simplify BlocksWithTransactionsMap type definitio…
MartinMinkov Aug 14, 2023
4757442
refactor(actions-service.ts): rename getActions to getActionData and …
MartinMinkov Aug 14, 2023
316bb7d
feat(actions-service.ts): add getActions method to handle empty actio…
MartinMinkov Aug 14, 2023
e5d3206
refactor(utils.ts): remove unused postgres import to clean up code
MartinMinkov Aug 14, 2023
76cbdb0
refactor(archive-node-adapter): remove unnecessary comments and redun…
MartinMinkov Aug 14, 2023
19a659e
refactor(events-service.ts): rename deriveEventsFromBlocks to blocksT…
MartinMinkov Aug 14, 2023
0fef6b6
refactor(utils.ts): remove sortParitionedBlocks function to improve p…
MartinMinkov Aug 14, 2023
878916c
refactor(types.ts): rename Transaction type to Transactions for bette…
MartinMinkov Aug 14, 2023
da4f9e7
refactor(actions-service.ts): rename blockMapEntries to blockTransact…
MartinMinkov Aug 14, 2023
ea1d727
refactor(utils.ts): remove type assertions and add explicit return ty…
MartinMinkov Aug 14, 2023
93a2735
feat(mina-consensus.ts): import and use config for subWindowsPerWindo…
MartinMinkov Aug 15, 2023
90b31ca
feat(consensus): add new config.ts file to handle consensus configura…
MartinMinkov Aug 16, 2023
17783bc
chore: remove console.log statements from events-service.ts and archi…
MartinMinkov Aug 16, 2023
c7294df
feat(consensus): Download consensus file and move tests
MartinMinkov Aug 16, 2023
eb5474b
feat(tsconfig.json): include 'tests/consensus/**/*' in tsconfig.json …
MartinMinkov Aug 16, 2023
89536d3
feat(config.ts): add path module to handle file paths in a cross-plat…
MartinMinkov Aug 16, 2023
59971af
feat(utils.ts): enhance removeRedundantEmittedFields function to hand…
MartinMinkov Aug 16, 2023
5f6403f
feat(tests): fix tests with big refactor
MartinMinkov Aug 16, 2023
05fa04b
feat(project): refactor project structure
MartinMinkov Aug 17, 2023
a6d76e5
refactor(utils.test.ts): move utils import path from 'db/archive-node…
MartinMinkov Aug 17, 2023
0232545
refactor(generate_mock_data.ts): update import paths for queries and …
MartinMinkov Aug 17, 2023
21a70db
feat(package.json): add 'clean' script to remove build directory for …
MartinMinkov Aug 17, 2023
4c962fd
feat(mina-consensus.ts): add compareWithCondition function to compare…
MartinMinkov Aug 18, 2023
17b7d6e
feat(blockchain/types.ts, blockchain/utils.ts, db/sql/events-actions/…
MartinMinkov Aug 18, 2023
419b37c
feat(blockchain): add nextEpochLockCheckpoint to BlockInfo for better…
MartinMinkov Aug 20, 2023
35b5482
docs(mina-consensus.ts): update comments for chain selection function…
MartinMinkov Aug 20, 2023
83880c0
feat(consensus): remove unused long fork rules
MartinMinkov Aug 22, 2023
f3de73c
refactor(actions-service.ts, events-service.ts): move utility functio…
MartinMinkov Aug 30, 2023
63a6938
refactor(tracing-service.ts): make spanStack and traceInfo readonly a…
MartinMinkov Aug 30, 2023
e9ccb94
refactor(tracing): move Jaeger tracing setup to separate module for b…
MartinMinkov Aug 30, 2023
42c094a
feat(index.ts): wrap main function in try-catch block to handle poten…
MartinMinkov Aug 30, 2023
e80e530
docs(mina-consensus.ts): update comments for select function to impro…
MartinMinkov Aug 30, 2023
1f0d0a0
feat(scripts): remove download_network_config.sh script as it is no l…
MartinMinkov Aug 30, 2023
3fb6201
feat(package.json): update all dependencies to their latest versions …
MartinMinkov Aug 30, 2023
b0245cd
refactor(jaeger-tracing.ts): rename tracer from 'archive-node-graphql…
MartinMinkov Aug 30, 2023
27ff391
refactor(resolvers.ts): rename span names for better traceability
MartinMinkov Aug 30, 2023
7923b9d
chore(package-lock.json): remove unused 'ws' package from node_module…
MartinMinkov Aug 30, 2023
1b3465c
fix(package-lock.json): fix deps
MartinMinkov Aug 30, 2023
b4468fd
refactor(utils.test.ts): update import path for utility functions to …
MartinMinkov Aug 30, 2023
8b92046
refactor(context.ts): remove getCurrentSpanFromGraphQLContext functio…
MartinMinkov Aug 31, 2023
9d0e809
refactor(plugins.ts): disable eslint rule for explicit any to allow a…
MartinMinkov Aug 31, 2023
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
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@graphql-tools/schema": "^9.0.16",
"@opentelemetry/exporter-jaeger": "^1.9.1",
"@opentelemetry/tracing": "^0.24.0",
"blakejs": "^1.2.1",
"dotenv": "^16.0.3",
"graphql": "^16.6.0",
"graphql-yoga": "3.7.0",
Expand Down
94 changes: 94 additions & 0 deletions src/db/archive-node-adapter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Event,
Events,
ArchiveNodeDatabaseRow,
BlockInfo,
BlocksWithTransactionsMap,
FieldElementIdWithValueMap,
} from '../../models/types';
Expand All @@ -30,6 +31,8 @@ import type {
} from '../../resolvers-types';
import { TraceInfo } from 'src/tracing';

import { blake2bHex } from 'blakejs';

export class ArchiveNodeAdapter implements DatabaseAdapter {
private client: postgres.Sql;

Expand Down Expand Up @@ -95,6 +98,7 @@ export class ArchiveNodeAdapter implements DatabaseAdapter {
elementIdFieldValues
);
eventsData.sort((a, b) => b.blockInfo.height - a.blockInfo.height);
filterBestTip(eventsData);
eventsProcessingSpan?.end();
return eventsData ?? [];
}
Expand Down Expand Up @@ -128,6 +132,7 @@ export class ArchiveNodeAdapter implements DatabaseAdapter {
elementIdFieldValues
);
actionsData.sort((a, b) => b.blockInfo.height - a.blockInfo.height);
filterBestTip(actionsData);
actionsProcessingSpan?.end();
return actionsData ?? [];
}
Expand Down Expand Up @@ -369,3 +374,92 @@ function findAllIndexes<T>(arr: T[], target: T): number[] {
});
return indexes;
}

function findLastIndexPredicate<T>(array: T[], predicate: (arg: T) => boolean) {
for (let i = 0; i < array.length; i++) {
console.log(array[i], predicate(array[i]));
if (
predicate(array[i]) &&
i < array.length - 1 &&
!predicate(array[i + 1])
) {
return i;
}
}
return -1;
}

function getAllPredicate<T>(array: T[], predicate: (arg: T) => boolean) {
const data: T[] = [];
for (let i = 0; i < array.length; i++) {
if (predicate(array[i])) {
data.push(array[i]);
} else {
break;
}
}
return data;
}

function filterBestTip<T extends { blockInfo: BlockInfo }>(
eventOrActionData: T[]
) {
const highestTipBlocks = getAllPredicate(
eventOrActionData,
(e) => e.blockInfo.distanceFromMaxBlockHeight === 0
);
if (highestTipBlocks.length > 1) {
const index = findLastIndexPredicate(
eventOrActionData,
(event) => event.blockInfo.distanceFromMaxBlockHeight === 0
);
if (index === -1) {
return eventOrActionData;
}
const selectedTip = chainSelect(highestTipBlocks);
eventOrActionData.splice(0, index + 1);
eventOrActionData.unshift(selectedTip);
}
}

function chainSelect<T extends { blockInfo: BlockInfo }>(blocks: T[]) {
if (blocks.length === 1) return blocks[0];
let existing = blocks[0];
for (let i = 1; i < blocks.length; i++) {
const candidate = blocks[i];
existing = select(existing, candidate);
}
return existing;
}

/**
* This function is used to select the best chain based on the tie breaker rules that the Mina Protocol uses.
*
* The tie breaker rules are as follows:
* 1. Take the block with the highest VRF output, denoted by comparing the VRF Blake2B hashes.
* - https://github.com/MinaProtocol/mina/blob/bff1e117ae4740fa51d12b32736c6c63d7909bd1/src/lib/consensus/proof_of_stake.ml#L3004
* 2. If the VRF outputs are equal, take the block with the highest state hash.
* - https://github.com/MinaProtocol/mina/blob/bff1e117ae4740fa51d12b32736c6c63d7909bd1/src/lib/consensus/proof_of_stake.ml#L3001
*
* The tie breaker rules are also more formally documented here: https://github.com/MinaProtocol/mina/blob/36d39cd0b2e3ba6c5e687770a5c683984ca587fc/docs/specs/consensus/README.md?plain=1#L1134
*/

function select<T extends { blockInfo: BlockInfo }>(existing: T, candidate: T) {
const existingVRFHash = blake2bHex(existing.blockInfo.lastVrfOutput);
const candidateVRFHash = blake2bHex(candidate.blockInfo.lastVrfOutput);
if (existingVRFHash > candidateVRFHash) {
return existing;
} else if (existingVRFHash < candidateVRFHash) {
return candidate;
}

const existingHash = existing.blockInfo.stateHash;
const candidateHash = candidate.blockInfo.stateHash;
if (existingHash > candidateHash) {
return existing;
} else if (existingHash < candidateHash) {
return candidate;
}

return existing;
}
13 changes: 7 additions & 6 deletions src/db/archive-node-adapter/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ function fullChainCTE(db_client: postgres.Sql) {
RECURSIVE pending_chain AS (
(
SELECT
id, state_hash, parent_hash, parent_id, height, global_slot_since_genesis, global_slot_since_hard_fork, timestamp, chain_status, ledger_hash
id, state_hash, parent_hash, parent_id, height, global_slot_since_genesis, global_slot_since_hard_fork, timestamp, chain_status, ledger_hash, last_vrf_output
FROM
blocks b
WHERE
height = (SELECT max(height) FROM blocks)
)
UNION ALL
SELECT
b.id, b.state_hash, b.parent_hash, b.parent_id, b.height, b.global_slot_since_genesis, b.global_slot_since_hard_fork, b.timestamp, b.chain_status, b.ledger_hash
b.id, b.state_hash, b.parent_hash, b.parent_id, b.height, b.global_slot_since_genesis, b.global_slot_since_hard_fork, b.timestamp, b.chain_status, b.ledger_hash, b.last_vrf_output
FROM
blocks b
INNER JOIN pending_chain ON b.id = pending_chain.parent_id
Expand All @@ -24,16 +24,16 @@ function fullChainCTE(db_client: postgres.Sql) {
),
full_chain AS (
SELECT
DISTINCT id, state_hash, parent_id, parent_hash, height, global_slot_since_genesis, global_slot_since_hard_fork, timestamp, chain_status, ledger_hash, (SELECT max(height) FROM blocks) - height AS distance_from_max_block_height
DISTINCT id, state_hash, parent_id, parent_hash, height, global_slot_since_genesis, global_slot_since_hard_fork, timestamp, chain_status, ledger_hash, (SELECT max(height) FROM blocks) - height AS distance_from_max_block_height, last_vrf_output
FROM
(
SELECT
id, state_hash, parent_id, parent_hash, height, global_slot_since_genesis, global_slot_since_hard_fork, timestamp, chain_status, ledger_hash
id, state_hash, parent_id, parent_hash, height, global_slot_since_genesis, global_slot_since_hard_fork, timestamp, chain_status, ledger_hash, last_vrf_output
FROM
pending_chain
UNION ALL
SELECT
id, state_hash, parent_id, parent_hash, height, global_slot_since_genesis, global_slot_since_hard_fork, timestamp, chain_status, ledger_hash
id, state_hash, parent_id, parent_hash, height, global_slot_since_genesis, global_slot_since_hard_fork, timestamp, chain_status, ledger_hash, last_vrf_output
FROM
blocks b
WHERE
Expand Down Expand Up @@ -84,7 +84,8 @@ function blocksAccessedCTE(
timestamp,
chain_status,
ledger_hash,
distance_from_max_block_height
distance_from_max_block_height,
last_vrf_output
FROM
account_identifier ai
INNER JOIN accounts_accessed aa ON ai.requesting_zkapp_account_identifier_id = aa.account_identifier_id
Expand Down
2 changes: 2 additions & 0 deletions src/models/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export type BlockInfo = {
globalSlotSinceHardfork: number;
globalSlotSinceGenesis: number;
distanceFromMaxBlockHeight: number;
lastVrfOutput: string;
};

export type TransactionInfo = {
Expand Down Expand Up @@ -93,6 +94,7 @@ export type ArchiveNodeDatabaseRow = {
field: string;
zkapp_event_element_ids: number[];
zkapp_event_array_id: number;
last_vrf_output: string;
action_state_value1?: string;
action_state_value2?: string;
action_state_value3?: string;
Expand Down
1 change: 1 addition & 0 deletions src/models/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export function createBlockInfo(row: ArchiveNodeDatabaseRow) {
globalSlotSinceHardfork: Number(row.global_slot_since_hard_fork),
globalSlotSinceGenesis: Number(row.global_slot_since_genesis),
distanceFromMaxBlockHeight: Number(row.distance_from_max_block_height),
lastVrfOutput: row.last_vrf_output,
} as BlockInfo;
}

Expand Down