Skip to content

Commit

Permalink
refactor(core-magistrate-transactions): require static fee (#3194)
Browse files Browse the repository at this point in the history
  • Loading branch information
spkjp committed Nov 21, 2019
1 parent 1fe6e1b commit bd57313
Show file tree
Hide file tree
Showing 14 changed files with 82 additions and 62 deletions.
8 changes: 8 additions & 0 deletions packages/core-kernel/src/contracts/shared/dynamic-fee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Interfaces } from "@arkecosystem/crypto";

export interface DynamicFeeContext {
transaction: Interfaces.ITransaction;
addonBytes: number;
satoshiPerByte: number;
height: number;
}
1 change: 1 addition & 0 deletions packages/core-kernel/src/contracts/shared/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./rounds";
export * from "./download-block";
export * from "./dynamic-fee";
6 changes: 6 additions & 0 deletions packages/core-magistrate-transactions/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,9 @@ export class BridgechainIsResignedError extends Errors.TransactionError {
super(`Failed to apply transaction, because bridgechain is resigned.`);
}
}

export class InvalidFeeError extends Errors.TransactionError {
constructor() {
super(`Failed to apply transaction, because fee is invalid.`);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ import {
Transactions as MagistrateTransactions,
} from "@arkecosystem/core-magistrate-crypto";
import { Handlers, TransactionReader } from "@arkecosystem/core-transactions";
import { Interfaces, Managers, Transactions, Utils } from "@arkecosystem/crypto";
import { Interfaces, Transactions, Utils } from "@arkecosystem/crypto";

import { BusinessIsResignedError, WalletIsNotBusinessError, BridgechainAlreadyRegisteredError } from "../errors";
import { MagistrateApplicationEvents } from "../events";
import { IBridgechainWalletAttributes, IBusinessWalletAttributes } from "../interfaces";
import { MagistrateIndex } from "../wallet-indexes";
import { BusinessRegistrationTransactionHandler } from "./business-registration";
import { MagistrateTransactionHandler } from "./magistrate-handler";

@Container.injectable()
export class BridgechainRegistrationTransactionHandler extends Handlers.TransactionHandler {
export class BridgechainRegistrationTransactionHandler extends MagistrateTransactionHandler {
public getConstructor(): Transactions.TransactionConstructor {
return MagistrateTransactions.BridgechainRegistrationTransaction;
}
Expand All @@ -27,10 +28,6 @@ export class BridgechainRegistrationTransactionHandler extends Handlers.Transact
return ["business.bridgechains.bridgechain"];
}

public async isActivated(): Promise<boolean> {
return Managers.configManager.getMilestone().aip11 === true;
}

public async bootstrap(): Promise<void> {
const reader: TransactionReader = this.getTransactionReader();
const transactions: Models.Transaction[] = await reader.read();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Container, Contracts, Utils } from "@arkecosystem/core-kernel";
import { Transactions as MagistrateTransactions, Enums } from "@arkecosystem/core-magistrate-crypto";
import { Interfaces as MagistrateInterfaces } from "@arkecosystem/core-magistrate-crypto";
import { Handlers, TransactionReader } from "@arkecosystem/core-transactions";
import { Interfaces, Managers, Transactions } from "@arkecosystem/crypto";
import { Interfaces, Transactions } from "@arkecosystem/crypto";

import {
BridgechainIsNotRegisteredError,
Expand All @@ -14,9 +14,10 @@ import {
import { MagistrateApplicationEvents } from "../events";
import { IBridgechainWalletAttributes, IBusinessWalletAttributes } from "../interfaces";
import { BridgechainRegistrationTransactionHandler } from "./bridgechain-registration";
import { MagistrateTransactionHandler } from "./magistrate-handler";

@Container.injectable()
export class BridgechainResignationTransactionHandler extends Handlers.TransactionHandler {
export class BridgechainResignationTransactionHandler extends MagistrateTransactionHandler {
public getConstructor(): Transactions.TransactionConstructor {
return MagistrateTransactions.BridgechainResignationTransaction;
}
Expand All @@ -29,10 +30,6 @@ export class BridgechainResignationTransactionHandler extends Handlers.Transacti
return ["business.bridgechains.bridgechain.resigned"];
}

public async isActivated(): Promise<boolean> {
return Managers.configManager.getMilestone().aip11 === true;
}

public async bootstrap(): Promise<void> {
const reader: TransactionReader = this.getTransactionReader();
const transactions: Models.Transaction[] = await reader.read();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Transactions as MagistrateTransactions,
} from "@arkecosystem/core-magistrate-crypto";
import { Handlers, TransactionReader } from "@arkecosystem/core-transactions";
import { Interfaces, Managers, Transactions } from "@arkecosystem/crypto";
import { Interfaces, Transactions } from "@arkecosystem/crypto";

import {
BridgechainIsNotRegisteredByWalletError,
Expand All @@ -17,9 +17,10 @@ import {
import { MagistrateApplicationEvents } from "../events";
import { IBridgechainWalletAttributes, IBusinessWalletAttributes } from "../interfaces";
import { BridgechainRegistrationTransactionHandler } from "./bridgechain-registration";
import { MagistrateTransactionHandler } from "./magistrate-handler";

@Container.injectable()
export class BridgechainUpdateTransactionHandler extends Handlers.TransactionHandler {
export class BridgechainUpdateTransactionHandler extends MagistrateTransactionHandler {
public getConstructor(): Transactions.TransactionConstructor {
return MagistrateTransactions.BridgechainUpdateTransaction;
}
Expand All @@ -32,10 +33,6 @@ export class BridgechainUpdateTransactionHandler extends Handlers.TransactionHan
return [];
}

public async isActivated(): Promise<boolean> {
return Managers.configManager.getMilestone().aip11 === true;
}

public async bootstrap(): Promise<void> {
const reader: TransactionReader = this.getTransactionReader();
const transactions: Models.Transaction[] = await reader.read();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import {
Enums,
} from "@arkecosystem/core-magistrate-crypto";
import { Handlers, TransactionReader } from "@arkecosystem/core-transactions";
import { Interfaces, Managers, Transactions, Utils } from "@arkecosystem/crypto";
import { Interfaces, Transactions, Utils } from "@arkecosystem/crypto";

import { BusinessAlreadyRegisteredError } from "../errors";
import { MagistrateApplicationEvents } from "../events";
import { IBusinessWalletAttributes } from "../interfaces";
import { MagistrateIndex } from "../wallet-indexes";
import { MagistrateTransactionHandler } from "./magistrate-handler";

@Container.injectable()
export class BusinessRegistrationTransactionHandler extends Handlers.TransactionHandler {
export class BusinessRegistrationTransactionHandler extends MagistrateTransactionHandler {
public getConstructor(): Transactions.TransactionConstructor {
return MagistrateTransactions.BusinessRegistrationTransaction;
}
Expand All @@ -33,10 +34,6 @@ export class BusinessRegistrationTransactionHandler extends Handlers.Transaction
];
}

public async isActivated(): Promise<boolean> {
return Managers.configManager.getMilestone().aip11 === true;
}

public async bootstrap(): Promise<void> {
const reader: TransactionReader = this.getTransactionReader();
const transactions: Models.Transaction[] = await reader.read();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import { Models } from "@arkecosystem/core-database";
import { Container, Contracts, Utils as AppUtils } from "@arkecosystem/core-kernel";
import { Transactions as MagistrateTransactions, Enums } from "@arkecosystem/core-magistrate-crypto";
import { Handlers, TransactionReader } from "@arkecosystem/core-transactions";
import { Interfaces, Managers, Transactions } from "@arkecosystem/crypto";
import { Interfaces, Transactions } from "@arkecosystem/crypto";

import { BusinessIsNotRegisteredError, BusinessIsResignedError } from "../errors";
import { MagistrateApplicationEvents } from "../events";
import { IBusinessWalletAttributes } from "../interfaces";
import { BusinessRegistrationTransactionHandler } from "./business-registration";
import { MagistrateTransactionHandler } from "./magistrate-handler";

@Container.injectable()
export class BusinessResignationTransactionHandler extends Handlers.TransactionHandler {
export class BusinessResignationTransactionHandler extends MagistrateTransactionHandler {
public getConstructor(): Transactions.TransactionConstructor {
return MagistrateTransactions.BusinessResignationTransaction;
}
Expand All @@ -23,10 +24,6 @@ export class BusinessResignationTransactionHandler extends Handlers.TransactionH
return [];
}

public async isActivated(): Promise<boolean> {
return Managers.configManager.getMilestone().aip11 === true;
}

public async bootstrap(): Promise<void> {
const reader: TransactionReader = this.getTransactionReader();
const transactions: Models.Transaction[] = await reader.read();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import {
Enums,
} from "@arkecosystem/core-magistrate-crypto";
import { Handlers, TransactionReader } from "@arkecosystem/core-transactions";
import { Interfaces, Managers, Transactions } from "@arkecosystem/crypto";
import { Interfaces, Transactions } from "@arkecosystem/crypto";

import { BusinessIsNotRegisteredError, BusinessIsResignedError } from "../errors";
import { MagistrateApplicationEvents } from "../events";
import { IBusinessWalletAttributes } from "../interfaces";
import { BusinessRegistrationTransactionHandler } from "./business-registration";
import { MagistrateTransactionHandler } from "./magistrate-handler";

@Container.injectable()
export class BusinessUpdateTransactionHandler extends Handlers.TransactionHandler {
export class BusinessUpdateTransactionHandler extends MagistrateTransactionHandler {
public getConstructor(): Transactions.TransactionConstructor {
return MagistrateTransactions.BusinessUpdateTransaction;
}
Expand All @@ -27,10 +28,6 @@ export class BusinessUpdateTransactionHandler extends Handlers.TransactionHandle
return [];
}

public async isActivated(): Promise<boolean> {
return Managers.configManager.getMilestone().aip11 === true;
}

public async bootstrap(): Promise<void> {
const reader: TransactionReader = this.getTransactionReader();
const transactions: Models.Transaction[] = await reader.read();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Handlers } from "@arkecosystem/core-transactions";
import { Interfaces as CryptoInterfaces, Managers, Utils } from "@arkecosystem/crypto";
import { Contracts } from "@arkecosystem/core-kernel";
import { InvalidFeeError } from "../errors";

export abstract class MagistrateTransactionHandler extends Handlers.TransactionHandler {
public async isActivated(): Promise<boolean> {
return Managers.configManager.getMilestone().aip11 === true;
}

public dynamicFee({ height }: Contracts.Shared.DynamicFeeContext): Utils.BigNumber {
return this.getConstructor().staticFee({ height });
}

public async throwIfCannotBeApplied(
transaction: CryptoInterfaces.ITransaction,
wallet: Contracts.State.Wallet,
customWalletRepository?: Contracts.State.WalletRepository,
): Promise<void> {
if (!transaction.data.fee.isEqualTo(this.getConstructor().staticFee())) {
throw new InvalidFeeError();
}

return super.throwIfCannotBeApplied(transaction, wallet, customWalletRepository);
}
}
21 changes: 15 additions & 6 deletions packages/core-transaction-pool/src/dynamic-fee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export const dynamicFeeMatcher = async (
.config()
.get<Record<string, any>>("dynamicFees");

const height: number = app.get<Contracts.State.StateStore>(Container.Identifiers.StateStore)
.getLastHeight();

AppUtils.assert.defined<Record<string, any>>(dynamicFees);

let broadcast: boolean;
Expand All @@ -31,18 +34,19 @@ export const dynamicFeeMatcher = async (
.get(transaction.type, transaction.typeGroup);

const addonBytes: number = dynamicFees.addonBytes[transaction.key];
const minFeeBroadcast: Utils.BigNumber = handler.dynamicFee(
const minFeeBroadcast: Utils.BigNumber = handler.dynamicFee({
transaction,
addonBytes,
dynamicFees.minFeeBroadcast,
);
satoshiPerByte: dynamicFees.minFeeBroadcast,
height,
});

if (fee.isGreaterThanEqual(minFeeBroadcast)) {
broadcast = true;

app.log.debug(
`Transaction ${id} eligible for broadcast - fee of ${Utils.formatSatoshi(fee)} is ${
fee.isEqualTo(minFeeBroadcast) ? "equal to" : "greater than"
fee.isEqualTo(minFeeBroadcast) ? "equal to" : "greater than"
} minimum fee (${Utils.formatSatoshi(minFeeBroadcast)})`,
);
} else {
Expand All @@ -55,14 +59,19 @@ export const dynamicFeeMatcher = async (
);
}

const minFeePool: Utils.BigNumber = handler.dynamicFee(transaction, addonBytes, dynamicFees.minFeePool);
const minFeePool: Utils.BigNumber = handler.dynamicFee({
transaction,
addonBytes,
satoshiPerByte: dynamicFees.minFeePool,
height
});

if (fee.isGreaterThanEqual(minFeePool)) {
enterPool = true;

app.log.debug(
`Transaction ${id} eligible to enter pool - fee of ${Utils.formatSatoshi(fee)} is ${
fee.isEqualTo(minFeePool) ? "equal to" : "greater than"
fee.isEqualTo(minFeePool) ? "equal to" : "greater than"
} minimum fee (${Utils.formatSatoshi(minFeePool)})`,
);
} else {
Expand Down
10 changes: 3 additions & 7 deletions packages/core-transactions/src/handlers/htlc-claim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,7 @@ export class HtlcClaimTransactionHandler extends TransactionHandler {
return Managers.configManager.getMilestone().aip11 === true;
}

public dynamicFee(
transaction: Interfaces.ITransaction,
addonBytes: number,
satoshiPerByte: number,
): Utils.BigNumber {
public dynamicFee(context: Contracts.Shared.DynamicFeeContext): Utils.BigNumber {
// override dynamicFee calculation as this is a zero-fee transaction
return Utils.BigNumber.ZERO;
}
Expand Down Expand Up @@ -242,10 +238,10 @@ export class HtlcClaimTransactionHandler extends TransactionHandler {
public async applyToRecipient(
transaction: Interfaces.ITransaction,
customWalletRepository?: Contracts.State.WalletRepository,
): Promise<void> {}
): Promise<void> { }

public async revertForRecipient(
transaction: Interfaces.ITransaction,
customWalletRepository?: Contracts.State.WalletRepository,
): Promise<void> {}
): Promise<void> { }
}
10 changes: 3 additions & 7 deletions packages/core-transactions/src/handlers/htlc-refund.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,7 @@ export class HtlcRefundTransactionHandler extends TransactionHandler {
return Managers.configManager.getMilestone().aip11 === true;
}

public dynamicFee(
transaction: Interfaces.ITransaction,
addonBytes: number,
satoshiPerByte: number,
): Utils.BigNumber {
public dynamicFee(context: Contracts.Shared.DynamicFeeContext): Utils.BigNumber {
// override dynamicFee calculation as this is a zero-fee transaction
return Utils.BigNumber.ZERO;
}
Expand Down Expand Up @@ -233,10 +229,10 @@ export class HtlcRefundTransactionHandler extends TransactionHandler {
public async applyToRecipient(
transaction: Interfaces.ITransaction,
customWalletRepository?: Contracts.State.WalletRepository,
): Promise<void> {}
): Promise<void> { }

public async revertForRecipient(
transaction: Interfaces.ITransaction,
customWalletRepository?: Contracts.State.WalletRepository,
): Promise<void> {}
): Promise<void> { }
}
8 changes: 2 additions & 6 deletions packages/core-transactions/src/handlers/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,7 @@ export abstract class TransactionHandler {

public abstract async isActivated(): Promise<boolean>;

public dynamicFee(
transaction: Interfaces.ITransaction,
addonBytes: number,
satoshiPerByte: number,
): Utils.BigNumber {
public dynamicFee({ addonBytes, satoshiPerByte, transaction }: Contracts.Shared.DynamicFeeContext): Utils.BigNumber {
addonBytes = addonBytes || 0;

if (satoshiPerByte <= 0) {
Expand Down Expand Up @@ -274,7 +270,7 @@ export abstract class TransactionHandler {
/**
* Database Service
*/
public emitEvents(transaction: Interfaces.ITransaction, emitter: Contracts.Kernel.Events.EventDispatcher): void {}
public emitEvents(transaction: Interfaces.ITransaction, emitter: Contracts.Kernel.Events.EventDispatcher): void { }

/**
* Transaction Pool logic
Expand Down

0 comments on commit bd57313

Please sign in to comment.