Skip to content

Commit

Permalink
feat(database): store height and totalRound (#756)
Browse files Browse the repository at this point in the history
* Add state storage

* Update lmdb

* Initialize database

* Cache commit not bytes

* Store state

* Get state

* Get total round from database
  • Loading branch information
sebastijankuzner authored Nov 8, 2024
1 parent 93da0da commit d5819c6
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 73 deletions.
18 changes: 1 addition & 17 deletions packages/bootstrap/source/bootstrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,9 @@ export class Bootstrapper {
if (this.databaseService.isEmpty()) {
await this.#processGenesisBlock();
} else {
await this.#processBlocks();

const commit = await this.databaseService.getLastCommit();
this.stateStore.setLastBlock(commit.block);
this.stateStore.setTotalRound(this.databaseService.getState().totalRound);
}

await this.validatorSet.restore();
Expand All @@ -127,21 +126,6 @@ export class Bootstrapper {
await this.databaseService.persist();
}

async #processBlocks(): Promise<void> {
const lastCommit = await this.databaseService.getLastCommit();

let totalRound = 0;

for await (const commit of this.databaseService.readCommits(
this.stateStore.getHeight(),
lastCommit.block.data.height,
)) {
totalRound += commit.proof.round + 1;
}

this.stateStore.setTotalRound(totalRound);
}

async #processCommit(commit: Contracts.Crypto.Commit): Promise<void> {
try {
const commitState = this.commitStateFactory(commit);
Expand Down
2 changes: 1 addition & 1 deletion packages/consensus-storage/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@mainsail/container": "workspace:*",
"@mainsail/contracts": "workspace:*",
"@mainsail/kernel": "workspace:*",
"lmdb": "3.0.4"
"lmdb": "3.1.4"
},
"devDependencies": {
"uvu": "^0.5.6"
Expand Down
7 changes: 7 additions & 0 deletions packages/contracts/source/contracts/database.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { Block } from "./crypto/block.js";
import { Commit } from "./crypto/commit.js";

export interface State {
height: number;
totalRound: number;
}

export interface DatabaseService {
initialize(): Promise<void>;
isEmpty(): boolean;

getState(): State;
getCommit(height: number): Promise<Commit | undefined>;
findCommitBuffers(start: number, end: number): Promise<Buffer[]>;
readCommits(start: number, end: number): AsyncGenerator<Commit>;
Expand Down
1 change: 1 addition & 0 deletions packages/contracts/source/identifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export const Identifiers = {
Service: Symbol("Database<Service>"),
Storage: {
Block: Symbol("Database<Storage.Block>"),
State: Symbol("Database<Storage.State>"),
},
},
Evm: {
Expand Down
2 changes: 1 addition & 1 deletion packages/database/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@mainsail/container": "workspace:*",
"@mainsail/contracts": "workspace:*",
"@mainsail/kernel": "workspace:*",
"lmdb": "3.0.4"
"lmdb": "3.1.4"
},
"devDependencies": {
"@types/tmp": "0.2.6",
Expand Down
43 changes: 35 additions & 8 deletions packages/database/source/database-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,35 @@ import * as lmdb from "lmdb";

@injectable()
export class DatabaseService implements Contracts.Database.DatabaseService {
@inject(Identifiers.Database.Root)
private readonly rootDb!: lmdb.RootDatabase;

@inject(Identifiers.Database.Storage.Block)
private readonly blockStorage!: lmdb.Database;

@inject(Identifiers.Database.Storage.State)
private readonly stateStorage!: lmdb.Database;

@inject(Identifiers.Cryptography.Commit.Factory)
private readonly commitFactory!: Contracts.Crypto.CommitFactory;

#cache = new Map<number, Buffer>();
#cache = new Map<number, Contracts.Crypto.Commit>();
#state = { height: 0, totalRound: 0 };

public async initialize(): Promise<void> {
if (this.isEmpty()) {
await this.rootDb.transaction(() => {
void this.stateStorage.put("state", this.#state);
});
await this.rootDb.flushed;
}

this.#state = this.stateStorage.get("state");
}

public getState(): Contracts.Database.State {
return this.#state;
}

public isEmpty(): boolean {
return this.#cache.size === 0 && this.blockStorage.getKeysCount() === 0;
Expand Down Expand Up @@ -77,7 +99,7 @@ export class DatabaseService implements Contracts.Database.DatabaseService {
}

if (this.#cache.size > 0) {
return await this.commitFactory.fromBytes([...this.#cache.values()].pop()!);
return [...this.#cache.values()].pop()!;
}

return await this.commitFactory.fromBytes(
Expand All @@ -86,24 +108,29 @@ export class DatabaseService implements Contracts.Database.DatabaseService {
}

public addCommit(commit: Contracts.Crypto.Commit): void {
this.#cache.set(commit.block.data.height, Buffer.from(commit.serialized, "hex"));
this.#cache.set(commit.block.data.height, commit);

this.#state.height = commit.block.data.height;
this.#state.totalRound += commit.proof.round + 1;
}

async persist(): Promise<void> {
await this.blockStorage.transaction(() => {
for (const [height, block] of this.#cache.entries()) {
void this.blockStorage.put(height, block);
await this.rootDb.transaction(() => {
for (const [height, commit] of this.#cache.entries()) {
void this.blockStorage.put(height, Buffer.from(commit.serialized, "hex"));
}

void this.stateStorage.put("state", this.#state);
});

await this.blockStorage.flushed;
await this.rootDb.flushed;

this.#cache.clear();
}

#get(height: number): Buffer {
if (this.#cache.has(height)) {
return this.#cache.get(height)!;
return Buffer.from(this.#cache.get(height)!.serialized, "hex");
}

return this.blockStorage.get(height);
Expand Down
6 changes: 5 additions & 1 deletion packages/database/source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ export class ServiceProvider extends Providers.ServiceProvider {
return true;
}

public async boot(): Promise<void> {
await this.app.get<Contracts.Database.DatabaseService>(Identifiers.Database.Service).initialize();
}

public async dispose(): Promise<void> {
await this.app.get<Contracts.Database.DatabaseService>(Identifiers.Database.Service).persist();

await this.app.get<RootDatabase>(Identifiers.Database.Root).close();
}

Expand All @@ -30,5 +33,6 @@ export class ServiceProvider extends Providers.ServiceProvider {
});
this.app.bind(Identifiers.Database.Root).toConstantValue(rootStorage);
this.app.bind(Identifiers.Database.Storage.Block).toConstantValue(rootStorage.openDB({ name: "blocks" }));
this.app.bind(Identifiers.Database.Storage.State).toConstantValue(rootStorage.openDB({ name: "state" }));
}
}
81 changes: 36 additions & 45 deletions pnpm-lock.yaml

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

0 comments on commit d5819c6

Please sign in to comment.