Skip to content

Commit

Permalink
feat(state): implements Service (#266)
Browse files Browse the repository at this point in the history
* Create service

* Inject and use StateService

* Use wallet repo factory

* Use wallet repo copy on write factory

* Drop WalletRepository identifier

* Don't store reference to wallet repostiroy in API

* Remove StateStore identifier

* Skip state tests

* Fix transactions tests

* Fix crypto-transaction-vote tests

* Fix crypto-messages tests

* Fix p2p tests

* Fix webhooks tests

* Fix transaction-pool tests

* Fix validator-set-static tests

* Fix consensus tests

* Fix validator-set-vote-weighted tests
  • Loading branch information
sebastijankuzner authored Oct 6, 2023
1 parent 1d7f9aa commit bca9bfd
Show file tree
Hide file tree
Showing 65 changed files with 354 additions and 266 deletions.
7 changes: 1 addition & 6 deletions packages/api-development/source/controllers/blockchain.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
// import { Utils } from "@mainsail/kernel";
import { inject } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";

import { Controller } from "./controller";

export class BlockchainController extends Controller {
@inject(Identifiers.StateStore)
private readonly stateStore!: Contracts.State.StateStore;

public async index() {
const { data } = this.stateStore.getLastBlock();
const { data } = this.stateService.getStateStore().getLastBlock();

return {
data: {
Expand Down
9 changes: 3 additions & 6 deletions packages/api-development/source/controllers/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ export class BlocksController extends Controller {
@inject(Identifiers.Database.Service)
private readonly database!: Contracts.Database.IDatabaseService;

@inject(Identifiers.StateStore)
private readonly stateStore!: Contracts.State.StateStore;

public async index(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const lastBlock = this.stateStore.getLastBlock();
const lastBlock = this.stateService.getStateStore().getLastBlock();

const pagination = this.getQueryPagination(request.query);

Expand Down Expand Up @@ -49,7 +46,7 @@ export class BlocksController extends Controller {
}

public async first(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const block = this.stateStore.getGenesisBlock();
const block = this.stateService.getStateStore().getGenesisBlock();

if (request.query.transform) {
return this.respondWithResource(block, BlockWithTransactionsResource, true);
Expand All @@ -59,7 +56,7 @@ export class BlocksController extends Controller {
}

public async last(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const block = this.stateStore.getLastBlock();
const block = this.stateService.getStateStore().getLastBlock();

if (request.query.transform) {
return this.respondWithResource(block, BlockWithTransactionsResource, true);
Expand Down
7 changes: 7 additions & 0 deletions packages/api-development/source/controllers/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ export class Controller {
@tagged("plugin", "api-development")
protected readonly apiConfiguration!: Providers.PluginConfiguration;

@inject(Identifiers.StateService)
protected readonly stateService!: Contracts.State.Service;

protected getWalletRepository(): Contracts.State.WalletRepository {
return this.stateService.getWalletRepository();
}

protected getQueryPagination(query: Hapi.RequestQuery): Pagination {
return {
limit: query.limit,
Expand Down
23 changes: 10 additions & 13 deletions packages/api-development/source/controllers/delegates.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import { Boom, notFound } from "@hapi/boom";
import Hapi from "@hapi/hapi";
import { inject, injectable, tagged } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { injectable } from "@mainsail/container";
import { Contracts } from "@mainsail/contracts";

import { WalletResource } from "../resources";
import { Controller } from "./controller";

@injectable()
export class DelegatesController extends Controller {
@inject(Identifiers.WalletRepository)
@tagged("state", "blockchain")
private readonly walletRepository!: Contracts.State.WalletRepository;

public index(request: Hapi.Request) {
const wallets = this.walletRepository.allByUsername();
const wallets = this.getWalletRepository().allByUsername();

const pagination = this.getQueryPagination(request.query);

Expand All @@ -33,12 +29,13 @@ export class DelegatesController extends Controller {

let wallet: Contracts.State.Wallet | undefined;

if (this.walletRepository.hasByAddress(walletId)) {
wallet = this.walletRepository.findByAddress(walletId);
} else if (this.walletRepository.hasByPublicKey(walletId)) {
wallet = await this.walletRepository.findByPublicKey(walletId);
} else if (this.walletRepository.hasByUsername(walletId)) {
wallet = this.walletRepository.findByUsername(walletId);
const walletRepository = this.getWalletRepository();
if (walletRepository.hasByAddress(walletId)) {
wallet = walletRepository.findByAddress(walletId);
} else if (walletRepository.hasByPublicKey(walletId)) {
wallet = await walletRepository.findByPublicKey(walletId);
} else if (walletRepository.hasByUsername(walletId)) {
wallet = walletRepository.findByUsername(walletId);
}

if (!wallet || !wallet.hasAttribute("validatorUsername")) {
Expand Down
9 changes: 3 additions & 6 deletions packages/api-development/source/controllers/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@ import { Controller } from "./controller";

@injectable()
export class NodeController extends Controller {
@inject(Identifiers.StateStore)
private readonly stateStore!: Contracts.State.StateStore;

@inject(Identifiers.P2P.Service)
private readonly p2pService!: Contracts.P2P.Service;

@inject(Identifiers.Cryptography.Configuration)
private readonly configuration!: Contracts.Crypto.IConfiguration;

public async status(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const lastBlock = this.stateStore.getLastBlock();
const lastBlock = this.stateService.getStateStore().getLastBlock();
const networkHeight = this.p2pService.getNetworkHeight();

return {
Expand All @@ -30,7 +27,7 @@ export class NodeController extends Controller {
}

public async syncing(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const lastBlock = this.stateStore.getLastBlock();
const lastBlock = this.stateService.getStateStore().getLastBlock();
const networkHeight = this.p2pService.getNetworkHeight();

return {
Expand All @@ -48,7 +45,7 @@ export class NodeController extends Controller {

return {
data: {
constants: this.configuration.getMilestone(this.stateStore.getLastHeight()),
constants: this.configuration.getMilestone(this.stateService.getStateStore().getLastHeight()),
core: {
version: this.app.version(),
},
Expand Down
23 changes: 10 additions & 13 deletions packages/api-development/source/controllers/wallets.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import { Boom, notFound } from "@hapi/boom";
import Hapi from "@hapi/hapi";
import { inject, injectable, tagged } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { injectable } from "@mainsail/container";
import { Contracts } from "@mainsail/contracts";

import { WalletResource } from "../resources";
import { Controller } from "./controller";

@injectable()
export class WalletsController extends Controller {
@inject(Identifiers.WalletRepository)
@tagged("state", "blockchain")
private readonly walletRepository!: Contracts.State.WalletRepository;

public index(request: Hapi.Request) {
const wallets = this.walletRepository.allByAddress();
const wallets = this.getWalletRepository().allByAddress();

const pagination = this.getQueryPagination(request.query);

Expand All @@ -33,12 +29,13 @@ export class WalletsController extends Controller {

let wallet: Contracts.State.Wallet | undefined;

if (this.walletRepository.hasByAddress(walletId)) {
wallet = this.walletRepository.findByAddress(walletId);
} else if (this.walletRepository.hasByPublicKey(walletId)) {
wallet = await this.walletRepository.findByPublicKey(walletId);
} else if (this.walletRepository.hasByUsername(walletId)) {
wallet = this.walletRepository.findByUsername(walletId);
const walletRepository = this.getWalletRepository();
if (walletRepository.hasByAddress(walletId)) {
wallet = walletRepository.findByAddress(walletId);
} else if (walletRepository.hasByPublicKey(walletId)) {
wallet = await walletRepository.findByPublicKey(walletId);
} else if (walletRepository.hasByUsername(walletId)) {
wallet = walletRepository.findByUsername(walletId);
}

if (!wallet) {
Expand Down
5 changes: 4 additions & 1 deletion packages/api-development/source/plugins/response-headers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { Contracts, Identifiers } from "@mainsail/contracts";
export const responseHeaders = {
getOnPreResponseHandler(app: Contracts.Kernel.Application) {
return (request: Hapi.Request, h: Hapi.ResponseToolkit): Hapi.Lifecycle.ReturnValue => {
const blockHeight = app.get<Contracts.State.StateStore>(Identifiers.StateStore).getLastHeight();
const blockHeight = app
.get<Contracts.State.Service>(Identifiers.StateService)
.getStateStore()
.getLastHeight();

const responsePropertyToUpdate = request.response.isBoom ? request.response.output : request.response;
responsePropertyToUpdate.headers = responsePropertyToUpdate.headers ?? {};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { inject, injectable, tagged } from "@mainsail/container";
import { inject, injectable } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { BigNumber } from "@mainsail/utils";

Expand All @@ -11,12 +11,8 @@ type BlockDataWithTransactionData = {

@injectable()
export class BlockWithTransactionsResource implements Resource {
@inject(Identifiers.WalletRepository)
@tagged("state", "blockchain")
private readonly walletRepository!: Contracts.State.WalletRepository;

@inject(Identifiers.StateStore)
private readonly stateStore!: Contracts.State.StateStore;
@inject(Identifiers.StateService)
private readonly stateService!: Contracts.State.Service;

public raw(resource: BlockDataWithTransactionData): object {
return JSON.parse(JSON.stringify(resource));
Expand All @@ -34,10 +30,10 @@ export class BlockWithTransactionsResource implements Resource {

// const totalAmountTransferred: Utils.BigNumber = blockData.totalAmount.plus(totalMultiPaymentTransferred);
const totalAmountTransferred: BigNumber = blockData.totalAmount;
const generator: Contracts.State.Wallet = await this.walletRepository.findByPublicKey(
blockData.generatorPublicKey,
);
const lastBlock: Contracts.Crypto.IBlock = this.stateStore.getLastBlock();
const generator: Contracts.State.Wallet = await this.stateService
.getWalletRepository()
.findByPublicKey(blockData.generatorPublicKey);
const lastBlock: Contracts.Crypto.IBlock = this.stateService.getStateStore().getLastBlock();

return {
confirmations: lastBlock ? lastBlock.data.height - blockData.height : 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { inject, injectable, tagged } from "@mainsail/container";
import { inject, injectable } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Utils as AppUtils } from "@mainsail/kernel";

Expand All @@ -11,12 +11,8 @@ type TransactionDataWithBlockData = {

@injectable()
export class TransactionWithBlockResource implements Resource {
@inject(Identifiers.WalletRepository)
@tagged("state", "blockchain")
protected readonly walletRepository!: Contracts.State.WalletRepository;

@inject(Identifiers.StateStore)
private readonly stateStore!: Contracts.State.StateStore;
@inject(Identifiers.StateService)
private readonly stateService!: Contracts.State.Service;

public raw(resource: TransactionDataWithBlockData): object {
return JSON.parse(JSON.stringify(resource));
Expand All @@ -28,10 +24,10 @@ export class TransactionWithBlockResource implements Resource {

AppUtils.assert.defined<string>(transactionData.senderPublicKey);

const wallet = await this.walletRepository.findByPublicKey(transactionData.senderPublicKey);
const wallet = await this.stateService.getWalletRepository().findByPublicKey(transactionData.senderPublicKey);
const sender: string = wallet.getAddress();
const recipient: string = transactionData.recipientId ?? sender;
const confirmations: number = this.stateStore.getLastHeight() - blockData.height + 1;
const confirmations: number = this.stateService.getStateStore().getLastHeight() - blockData.height + 1;

return {
amount: transactionData.amount.toFixed(),
Expand Down
9 changes: 4 additions & 5 deletions packages/api-development/source/resources/transaction.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { inject, injectable, tagged } from "@mainsail/container";
import { inject, injectable } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Utils as AppUtils } from "@mainsail/kernel";

import { Resource } from "../types";

@injectable()
export class TransactionResource implements Resource {
@inject(Identifiers.WalletRepository)
@tagged("state", "blockchain")
protected readonly walletRepository!: Contracts.State.WalletRepository;
@inject(Identifiers.StateService)
private readonly stateService!: Contracts.State.Service;

public raw(resource: Contracts.Crypto.ITransactionData): object {
return JSON.parse(JSON.stringify(resource));
Expand All @@ -17,7 +16,7 @@ export class TransactionResource implements Resource {
public async transform(resource: Contracts.Crypto.ITransactionData): Promise<object> {
AppUtils.assert.defined<string>(resource.senderPublicKey);

const wallet = await this.walletRepository.findByPublicKey(resource.senderPublicKey);
const wallet = await this.stateService.getWalletRepository().findByPublicKey(resource.senderPublicKey);
const sender: string = wallet.getAddress();

return {
Expand Down
6 changes: 3 additions & 3 deletions packages/api-sync/source/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ export class Sync implements Contracts.ApiSync.ISync {
@inject(ApiDatabaseIdentifiers.WalletRepositoryFactory)
private readonly walletRepositoryFactory!: ApiDatabaseContracts.IWalletRepositoryFactory;

@inject(Identifiers.StateStore)
private readonly stateStore!: Contracts.State.StateStore;
@inject(Identifiers.StateService)
private readonly stateService!: Contracts.State.Service;

@inject(Identifiers.ValidatorSet)
private readonly validatorSet!: Contracts.ValidatorSet.IValidatorSet;
Expand Down Expand Up @@ -168,7 +168,7 @@ export class Sync implements Contracts.ApiSync.ISync {
}

async #bootstrapState(): Promise<void> {
const genesisBlock = this.stateStore.getGenesisBlock();
const genesisBlock = this.stateService.getStateStore().getGenesisBlock();
await this.stateRepositoryFactory()
.createQueryBuilder()
.insert()
Expand Down
31 changes: 17 additions & 14 deletions packages/bootstrap/source/bootstrapper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { inject, injectable, optional, tagged } from "@mainsail/container";
import { inject, injectable, optional, postConstruct } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Utils } from "@mainsail/kernel";

Expand Down Expand Up @@ -31,15 +31,11 @@ export class Bootstrapper {
@inject(Identifiers.Cryptography.Configuration)
private readonly configuration!: Contracts.Crypto.IConfiguration;

@inject(Identifiers.StateStore)
private readonly stateStore!: Contracts.State.StateStore;

@inject(Identifiers.Database.Service)
private readonly databaseService!: Contracts.Database.IDatabaseService;

@inject(Identifiers.WalletRepository)
@tagged("state", "blockchain")
private walletRepository!: Contracts.State.WalletRepository;
@inject(Identifiers.StateService)
private stateService!: Contracts.State.Service;

@inject(Identifiers.Consensus.ProposerPicker)
private readonly proposerPicker!: Contracts.Consensus.IProposerPicker;
Expand All @@ -57,6 +53,13 @@ export class Bootstrapper {
@optional()
private readonly apiSync: Contracts.ApiSync.ISync | undefined;

#stateStore!: Contracts.State.StateStore;

@postConstruct()
public initialize(): void {
this.#stateStore = this.stateService.getStateStore();
}

public async bootstrap(): Promise<void> {
try {
await this.#setGenesisBlock();
Expand All @@ -70,7 +73,7 @@ export class Bootstrapper {
}

await this.#processBlocks();
this.stateStore.setBootstrap(false);
this.#stateStore.setBootstrap(false);

this.stateVerifier.verifyWalletsConsistency();

Expand All @@ -89,13 +92,13 @@ export class Bootstrapper {
const genesisBlockJson = this.configuration.get("genesisBlock");
const genesisBlock = await this.blockFactory.fromCommittedJson(genesisBlockJson);

this.stateStore.setGenesisBlock(genesisBlock);
this.stateStore.setLastBlock(genesisBlock.block);
this.#stateStore.setGenesisBlock(genesisBlock);
this.#stateStore.setLastBlock(genesisBlock.block);
}

async #storeGenesisBlock(): Promise<void> {
if (!(await this.databaseService.getLastBlock())) {
const genesisBlock = this.stateStore.getGenesisBlock();
const genesisBlock = this.#stateStore.getGenesisBlock();
await this.databaseService.saveBlocks([genesisBlock]);
}
}
Expand All @@ -109,16 +112,16 @@ export class Bootstrapper {
)
.getRegisteredHandlers();

const genesisBlock = this.stateStore.getGenesisBlock();
const genesisBlock = this.#stateStore.getGenesisBlock();
for (const handler of registeredHandlers.values()) {
await handler.bootstrap(this.walletRepository, genesisBlock.block.transactions);
await handler.bootstrap(this.stateService.getWalletRepository(), genesisBlock.block.transactions);
}
}

async #initState(): Promise<void> {
await this.validatorSet.initialize();

const committedBlockState = this.committedBlockStateFactory(this.stateStore.getGenesisBlock());
const committedBlockState = this.committedBlockStateFactory(this.#stateStore.getGenesisBlock());
await this.proposerPicker.onCommit(committedBlockState);
}

Expand Down
Loading

0 comments on commit bca9bfd

Please sign in to comment.