Skip to content

Commit

Permalink
refactor(processor): log verification errors (#452)
Browse files Browse the repository at this point in the history
* Remove console logs

* Remove forger errors

* Remove UnexpectedError

* Remove extra exceptions

* Add ValidatorExceptions

* Handler throws errors

* Improve logs

* style: resolve style guide violations

---------

Co-authored-by: sebastijankuzner <[email protected]>
  • Loading branch information
sebastijankuzner and sebastijankuzner authored Feb 26, 2024
1 parent f72fc66 commit 035a4a8
Show file tree
Hide file tree
Showing 18 changed files with 81 additions and 123 deletions.
2 changes: 0 additions & 2 deletions packages/api-http/test/helpers/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ export const request = async <T = Record<string, any>>(
}

const response = await got(`http://localhost:4003/api/${path}${transform}`);
// console.log(response);

const { statusCode, headers, body } = response;
return { statusCode, headers, data: JSON.parse(body) as T };
};
2 changes: 1 addition & 1 deletion packages/bootstrap/source/bootstrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export class Bootstrapper {
const commitState = this.commitStateFactory(commit);
const result = await this.blockProcessor.process(commitState);
if (result === false) {
throw new Error(`Cannot process block`);
throw new Error(`Block is not processed.`);
}
await this.blockProcessor.commit(commitState);
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ export class GenesisBlockGenerator extends Generator {

const verified = await this.blockVerifier.verify(genesis.block);
if (!verified.verified) {
console.log(verified);
throw new Error("failed to generate genesis block");
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/contracts/source/contracts/processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export interface ProcessableUnit {
}

export interface Handler {
execute(unit: ProcessableUnit): Promise<boolean>;
execute(unit: ProcessableUnit): Promise<void>;
}

export interface BlockProcessor {
Expand All @@ -28,5 +28,5 @@ export interface TransactionProcessor {
}

export interface Verifier {
verify(unit: ProcessableUnit): Promise<boolean>;
verify(unit: ProcessableUnit): Promise<void>;
}
13 changes: 0 additions & 13 deletions packages/contracts/source/exceptions/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,3 @@ export class Exception extends Error {
Error.captureStackTrace(this, this.constructor);
}
}

export class UnexpectedError extends Exception {
public constructor(
public readonly error: Error,
public readonly path: string[],
) {
super(
path.length > 0
? `Unexpected error '${error.message}' (${error.constructor.name}) at '${path.join(".")}'`
: `Unexpected error '${error.message}' (${error.constructor.name})`,
);
}
}
5 changes: 0 additions & 5 deletions packages/contracts/source/exceptions/cache.ts

This file was deleted.

13 changes: 0 additions & 13 deletions packages/contracts/source/exceptions/forger.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/contracts/source/exceptions/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
export * from "./base";
export * from "./cache";
export * from "./cli";
export * from "./config";
export * from "./consensus";
export * from "./container";
export * from "./crypto";
export * from "./filesystem";
export * from "./forger";
export * from "./logic";
export * from "./p2p";
export * from "./plugins";
export * from "./pool";
export * from "./processor";
export * from "./runtime";
export * from "./state";
export * from "./validation";
42 changes: 42 additions & 0 deletions packages/contracts/source/exceptions/processor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Block } from "../contracts/crypto";
import { Exception } from "./base";

export class ValidatorException extends Exception {}

export class BlockNotChained extends ValidatorException {
public constructor(block: Block) {
super(`Block ${block.data.id} is not chained.`);
}
}

export class BlockNotVerified extends ValidatorException {
public constructor(block: Block, reason: string) {
super(`Block ${block.data.id} is not verified, because: ${reason}.`);
}
}

export class InvalidTimestamp extends ValidatorException {
public constructor(block: Block) {
super(`Block ${block.data.id} timestamp is too low.`);
}
}

export class InvalidGenerator extends ValidatorException {
public constructor(block: Block, expectedValidator: string) {
super(
`Block ${block.data.id} has invalid generator. Block generator is ${block.data.generatorPublicKey} instead ${expectedValidator}.`,
);
}
}

export class IncompatibleTransactions extends ValidatorException {
public constructor(block: Block) {
super(`Block ${block.data.id} contains incompatible transaction.`);
}
}

export class InvalidNonce extends ValidatorException {
public constructor(block: Block, sender: string) {
super(`Block ${block.data.id} contains invalid nonce for sender ${sender}.`);
}
}
8 changes: 0 additions & 8 deletions packages/contracts/source/exceptions/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@ import { Exception } from "./base";

export class RuntimeException extends Exception {}

export class OverflowException extends RuntimeException {}

export class RangeException extends RuntimeException {}

export class UnderflowException extends RuntimeException {}

export class UnexpectedValueException extends RuntimeException {}

export class NotImplemented extends RuntimeException {
public constructor(method: string, klass: string) {
super(`Method [${method}] is not implemented in [${klass}].`);
Expand Down
7 changes: 2 additions & 5 deletions packages/processor/source/block-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ export class BlockProcessor implements Contracts.Processor.BlockProcessor {

public async process(unit: Contracts.Processor.ProcessableUnit): Promise<boolean> {
try {
if (!(await this.verifier.verify(unit))) {
return false;
}
await this.verifier.verify(unit);

for (const transaction of unit.getBlock().transactions) {
await this.transactionProcessor.process(unit.store.walletRepository, transaction);
Expand All @@ -65,8 +63,7 @@ export class BlockProcessor implements Contracts.Processor.BlockProcessor {

return true;
} catch (error) {
console.log(error);
this.logger.error(`Cannot process block, because: ${error.message}`);
this.logger.error(`Cannot process block because: ${error.message}`);
}

return false;
Expand Down
28 changes: 7 additions & 21 deletions packages/processor/source/block-verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,17 @@ export class BlockVerifier implements Contracts.Processor.Verifier {
@inject(Identifiers.Application.Instance)
protected readonly app!: Contracts.Kernel.Application;

public async verify(unit: Contracts.Processor.ProcessableUnit): Promise<boolean> {
if (!(await this.app.resolve(ChainedVerifier).execute(unit))) {
return false;
}
public async verify(unit: Contracts.Processor.ProcessableUnit): Promise<void> {
await this.app.resolve(ChainedVerifier).execute(unit);

if (!(await this.app.resolve(TimestampVerifier).execute(unit))) {
return false;
}
await this.app.resolve(TimestampVerifier).execute(unit);

if (!(await this.app.resolve(GeneratorVerifier).execute(unit))) {
return false;
}
await this.app.resolve(GeneratorVerifier).execute(unit);

if (!(await this.app.resolve(VerifyBlockVerifier).execute(unit))) {
return false;
}
await this.app.resolve(VerifyBlockVerifier).execute(unit);

if (!(await this.app.resolve(IncompatibleTransactionsVerifier).execute(unit))) {
return false;
}
await this.app.resolve(IncompatibleTransactionsVerifier).execute(unit);

if (!(await this.app.resolve(NonceVerifier).execute(unit))) {
return false;
}

return true;
await this.app.resolve(NonceVerifier).execute(unit);
}
}
10 changes: 6 additions & 4 deletions packages/processor/source/verifiers/chained-verifier.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { inject, injectable } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Contracts, Exceptions, Identifiers } from "@mainsail/contracts";
import { Utils } from "@mainsail/kernel";

@injectable()
Expand All @@ -10,11 +10,13 @@ export class ChainedVerifier implements Contracts.Processor.Handler {
@inject(Identifiers.State.Service)
private readonly stateService!: Contracts.State.Service;

public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<boolean> {
public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<void> {
if (unit.getBlock().data.height === 0) {
return true;
return;
}

return Utils.isBlockChained(this.stateService.getStore().getLastBlock().data, unit.getBlock().data);
if (!Utils.isBlockChained(this.stateService.getStore().getLastBlock().data, unit.getBlock().data)) {
throw new Exceptions.BlockNotChained(unit.getBlock());
}
}
}
10 changes: 6 additions & 4 deletions packages/processor/source/verifiers/generator-verifier.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { inject, injectable } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Contracts, Exceptions, Identifiers } from "@mainsail/contracts";

@injectable()
export class GeneratorVerifier implements Contracts.Processor.Handler {
Expand All @@ -12,14 +12,16 @@ export class GeneratorVerifier implements Contracts.Processor.Handler {
@inject(Identifiers.ValidatorSet.Service)
private readonly validatorSet!: Contracts.ValidatorSet.Service;

public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<boolean> {
public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<void> {
if (unit.getBlock().data.height === 0) {
return true;
return;
}

const validatorIndex = this.proposerSelector.getValidatorIndex(unit.getBlock().data.round);
const validator = this.validatorSet.getValidator(validatorIndex);

return unit.getBlock().data.generatorPublicKey === validator.getWalletPublicKey();
if (unit.getBlock().data.generatorPublicKey !== validator.getWalletPublicKey()) {
throw new Exceptions.InvalidGenerator(unit.getBlock(), validator.getWalletPublicKey());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { injectable } from "@mainsail/container";
import { Contracts } from "@mainsail/contracts";
import { Contracts, Exceptions } from "@mainsail/contracts";

@injectable()
export class IncompatibleTransactionsVerifier implements Contracts.Processor.Handler {
public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<boolean> {
public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<void> {
const block = unit.getBlock();

for (let index = 1; index < block.transactions.length; index++) {
if (block.transactions[index].data.version !== block.transactions[0].data.version) {
return false;
throw new Exceptions.IncompatibleTransactions(block);
}
}

return true;
}
}
17 changes: 3 additions & 14 deletions packages/processor/source/verifiers/nonce-verifier.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { inject, injectable } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Contracts, Exceptions, Identifiers } from "@mainsail/contracts";
import { Utils } from "@mainsail/kernel";
import { BigNumber } from "@mainsail/utils";

Expand All @@ -8,10 +8,7 @@ export class NonceVerifier implements Contracts.Processor.Handler {
@inject(Identifiers.Application.Instance)
protected readonly app!: Contracts.Kernel.Application;

@inject(Identifiers.Services.Log.Service)
private readonly logger!: Contracts.Kernel.Logger;

public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<boolean> {
public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<void> {
const block = unit.getBlock();

const nonceBySender = {};
Expand All @@ -33,18 +30,10 @@ export class NonceVerifier implements Contracts.Processor.Handler {
const nonce: BigNumber = BigNumber.make(data.nonce);

if (!nonceBySender[sender].plus(1).isEqualTo(nonce)) {
this.logger.warning(
`Block { height: ${block.data.height.toLocaleString()}, id: ${block.data.id} } ` +
`not accepted: invalid nonce order for sender ${sender}: ` +
`preceding nonce: ${nonceBySender[sender].toFixed(0)}, ` +
`transaction ${data.id} has nonce ${nonce.toFixed()}.`,
);
return false;
throw new Exceptions.InvalidNonce(block, sender);
}

nonceBySender[sender] = nonce;
}

return true;
}
}
10 changes: 4 additions & 6 deletions packages/processor/source/verifiers/timestamp-verifier.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { inject, injectable } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Contracts, Exceptions, Identifiers } from "@mainsail/contracts";
import { Utils } from "@mainsail/kernel";

@injectable()
Expand All @@ -16,9 +16,9 @@ export class TimestampVerifier implements Contracts.Processor.Handler {
@inject(Identifiers.Services.Log.Service)
private readonly logger!: Contracts.Kernel.Logger;

public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<boolean> {
public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<void> {
if (unit.getBlock().data.height === 0) {
return true;
return;
}

if (
Expand All @@ -33,9 +33,7 @@ export class TimestampVerifier implements Contracts.Processor.Handler {
`Block ${unit.getBlock().data.height.toLocaleString()} disregarded, because it's timestamp is too low`,
);

return false;
throw new Exceptions.InvalidTimestamp(unit.getBlock());
}

return true;
}
}
21 changes: 4 additions & 17 deletions packages/processor/source/verifiers/verify-block-verifier.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { inject, injectable } from "@mainsail/container";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Contracts, Exceptions, Identifiers } from "@mainsail/contracts";

@injectable()
export class VerifyBlockVerifier implements Contracts.Processor.Handler {
Expand All @@ -12,10 +12,7 @@ export class VerifyBlockVerifier implements Contracts.Processor.Handler {
@inject(Identifiers.Transaction.Handler.Registry)
private readonly handlerRegistry!: Contracts.Transactions.TransactionHandlerRegistry;

@inject(Identifiers.Services.Log.Service)
private readonly logger!: Contracts.Kernel.Logger;

public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<boolean> {
public async execute(unit: Contracts.Processor.ProcessableUnit): Promise<void> {
const block = unit.getBlock();

let verification: Contracts.Crypto.BlockVerification = await this.blockVerifier.verify(block);
Expand All @@ -30,22 +27,12 @@ export class VerifyBlockVerifier implements Contracts.Processor.Handler {
// @TODO: check if we can remove this duplicate verification
verification = await this.blockVerifier.verify(block);
} catch (error) {
this.logger.warning(`Failed to verify block, because: ${error.message}`);
throw new Exceptions.BlockNotVerified(block, error.message);
}
}

if (!verification.verified) {
this.logger.warning(
`Block ${block.data.height.toLocaleString()} (${
block.data.id
}) disregarded because verification failed`,
);

this.logger.warning(JSON.stringify(verification, undefined, 4));

return false;
throw new Exceptions.BlockNotVerified(block, verification.errors.join(", "));
}

return true;
}
}

0 comments on commit 035a4a8

Please sign in to comment.