-
-
Notifications
You must be signed in to change notification settings - Fork 291
/
utils.ts
115 lines (105 loc) · 3.65 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import {allForks} from "@lodestar/types";
import {routes} from "@lodestar/api";
import {blockToHeader} from "@lodestar/state-transition";
import {ChainForkConfig} from "@lodestar/config";
import {IForkChoice} from "@lodestar/fork-choice";
import {fromHexString} from "@chainsafe/ssz";
import {IBeaconDb} from "../../../../db/index.js";
import {GENESIS_SLOT} from "../../../../constants/index.js";
import {ApiError, ValidationError} from "../../errors.js";
import {isOptimisticBlock} from "../../../../util/forkChoice.js";
export function toBeaconHeaderResponse(
config: ChainForkConfig,
block: allForks.SignedBeaconBlock,
canonical = false
): routes.beacon.BlockHeaderResponse {
return {
root: config.getForkTypes(block.message.slot).BeaconBlock.hashTreeRoot(block.message),
canonical,
header: {
message: blockToHeader(config, block.message),
signature: block.signature,
},
};
}
export async function resolveBlockId(
forkChoice: IForkChoice,
db: IBeaconDb,
blockId: routes.beacon.BlockId
): Promise<{block: allForks.SignedBeaconBlock; executionOptimistic: boolean}> {
const {block, executionOptimistic} = await resolveBlockIdOrNull(forkChoice, db, blockId);
if (!block) {
throw new ApiError(404, `No block found for id '${blockId}'`);
}
return {block, executionOptimistic};
}
async function resolveBlockIdOrNull(
forkChoice: IForkChoice,
db: IBeaconDb,
blockId: routes.beacon.BlockId
): Promise<{block: allForks.SignedBeaconBlock | null; executionOptimistic: boolean}> {
blockId = String(blockId).toLowerCase();
if (blockId === "head") {
const head = forkChoice.getHead();
return {
block: await db.block.get(fromHexString(head.blockRoot)),
executionOptimistic: isOptimisticBlock(head),
};
}
if (blockId === "genesis") {
return {
block: await db.blockArchive.get(GENESIS_SLOT),
executionOptimistic: false,
};
}
if (blockId === "finalized") {
return {
block: await db.blockArchive.get(forkChoice.getFinalizedBlock().slot),
executionOptimistic: false,
};
}
if (blockId === "justified") {
const justified = forkChoice.getJustifiedBlock();
return {
block: await db.block.get(fromHexString(justified.blockRoot)),
executionOptimistic: false,
};
}
let blockSummary;
let getBlockByBlockArchive;
if (blockId.startsWith("0x")) {
const blockHash = fromHexString(blockId);
blockSummary = forkChoice.getBlock(blockHash);
getBlockByBlockArchive = async () => db.blockArchive.getByRoot(blockHash);
} else {
// block id must be slot
const blockSlot = parseInt(blockId, 10);
if (isNaN(blockSlot) && isNaN(blockSlot - 0)) {
throw new ValidationError(`Invalid block id '${blockId}'`, "blockId");
}
blockSummary = forkChoice.getCanonicalBlockAtSlot(blockSlot);
getBlockByBlockArchive = async () => db.blockArchive.get(blockSlot);
}
if (blockSummary) {
// All unfinalized blocks **and the finalized block** are tracked by the fork choice.
// Unfinalized blocks are stored in the block repository, but the finalized block is in the block archive
const finalized = forkChoice.getFinalizedBlock();
if (blockSummary.slot === finalized.slot) {
return {
block: await db.blockArchive.get(finalized.slot),
executionOptimistic: isOptimisticBlock(blockSummary),
};
} else {
return {
block: await db.block.get(fromHexString(blockSummary.blockRoot)),
executionOptimistic: false,
};
}
} else {
// Blocks not in the fork choice are in the block archive
return {
block: await getBlockByBlockArchive(),
executionOptimistic: false,
};
}
}