Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/contracts/source/contracts/crypto/identities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,5 @@ export interface SignatureEcdsa {
signRecoverable(message: Buffer, privateKey: Buffer): Promise<EcdsaSignature>;
verifyRecoverable(signature: EcdsaSignature, message: Buffer, publicKey: Buffer): Promise<boolean>;
recoverPublicKey(message: Buffer, signature: EcdsaSignature): string;
isLowS(signature: EcdsaSignature): boolean;
}
1 change: 0 additions & 1 deletion packages/contracts/source/contracts/evm/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ export interface PreverifyTransactionContext {
readonly nonce: bigint;
readonly data: Buffer;
readonly txHash: string;
readonly index?: number;
readonly specId: SpecId;
readonly blockGasLimit: bigint;
}
Expand Down
24 changes: 1 addition & 23 deletions packages/contracts/source/contracts/transactions.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import type { Transaction, TransactionData } from "./crypto/index.js";
import type { Transaction } from "./crypto/index.js";
import type { BlockContext, Instance, TransactionReceipt } from "./evm/index.js";
import type { Wallet } from "./state/index.js";

export type TransactionHandlerConstructor = new () => TransactionHandler;

export type TransactionHandlerContext = {
evm: {
instance: Instance;
Expand All @@ -12,27 +10,7 @@ export type TransactionHandlerContext = {
};

export interface TransactionHandler {
verify(transaction: Transaction): Promise<boolean>;

throwIfCannotBeApplied(transaction: Transaction, sender: Wallet, evm: Instance): Promise<void>;

apply(context: TransactionHandlerContext, transaction: Transaction): Promise<TransactionReceipt>;
}

export interface TransactionHandlerRegistry {
getRegisteredHandlers(): TransactionHandler[];

getRegisteredHandlerByType(type: number, version?: number): TransactionHandler;

getActivatedHandlers(): Promise<TransactionHandler[]>;

getActivatedHandlerByType(type: number, version?: number): Promise<TransactionHandler>;

getActivatedHandlerForData(transactionData: TransactionData): Promise<TransactionHandler>;
}

export interface TransactionHandlerProvider {
isRegistrationRequired(): boolean;

registerHandlers(): void;
}
9 changes: 6 additions & 3 deletions packages/crypto-signature-ecdsa/source/signature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ export class Signature implements Contracts.Crypto.SignatureEcdsa {
message: Buffer,
publicKey: Buffer,
): Promise<boolean> {
const signatureRS = Buffer.from(signature.r + signature.s, "hex");
if (!secp256k1.isLowS(signatureRS)) {
if (!this.isLowS(signature)) {
return false;
}

return secp256k1.verify(message, signatureRS, publicKey);
return secp256k1.verify(message, Buffer.from(signature.r + signature.s, "hex"), publicKey);
}

public isLowS(signature: Contracts.Crypto.EcdsaSignature): boolean {
return secp256k1.isLowS(Buffer.from(signature.r + signature.s, "hex"));
}

public recoverPublicKey(message: Buffer, signature: Contracts.Crypto.EcdsaSignature): string {
Expand Down
8 changes: 6 additions & 2 deletions packages/crypto-transaction/source/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class TransactionFactory implements Contracts.Crypto.TransactionFactory {

@inject(Identifiers.Cryptography.Signature.Instance)
@tagged("type", "wallet")
private readonly signatureSerializer!: Contracts.Crypto.SignatureEcdsa;
private readonly signatureEcdsa!: Contracts.Crypto.SignatureEcdsa;

@inject(Identifiers.Cryptography.Transaction.Deserializer)
private readonly deserializer!: Contracts.Crypto.TransactionDeserializer;
Expand Down Expand Up @@ -101,10 +101,14 @@ export class TransactionFactory implements Contracts.Crypto.TransactionFactory {
assert.string(data.r);
assert.string(data.s);

if (!this.signatureEcdsa.isLowS({ r: data.r, s: data.s, v: data.v })) {
throw new InvalidTransactionBytesError("non-canonical signature (high S value)");
}

const unsignedHash = await this.hashFactory.toHashUnsigned(data);
const hash = await this.hashFactory.toHash(data);

const senderPublicKey = this.signatureSerializer.recoverPublicKey(unsignedHash, {
const senderPublicKey = this.signatureEcdsa.recoverPublicKey(unsignedHash, {
r: data.r,
s: data.s,
v: data.v,
Expand Down
1 change: 0 additions & 1 deletion packages/evm/bindings/src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ pub struct JsTransactionContext {
pub nonce: BigInt,
pub data: Buffer,
pub tx_hash: String,
pub index: Option<u32>,
pub block_context: JsBlockContext,
pub spec_id: String,
}
Expand Down
12 changes: 6 additions & 6 deletions packages/exceptions/source/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ export class EvmCallMissingRecipientError extends Exception {
}
}

export class EvmCallFailedError extends Exception {
public constructor(transaction: Contracts.Crypto.Transaction, error: Error) {
super(`invalid EVM call for tx ${transaction.hash}: ${error.message}`);
}
}

export class InvalidMilestoneConfigurationError extends Exception {
public constructor(message: string) {
super(message);
Expand Down Expand Up @@ -334,12 +340,6 @@ export class NotEnoughValidatorsError extends Exception {
}
}

export class InvalidSignatureError extends Exception {
public constructor() {
super(`Failed to apply transaction, because signature is invalid.`);
}
}

export class MultiPaymentAmountMismatchError extends Exception {
public constructor() {
super(`Payment amounts mismatch.`);
Expand Down
13 changes: 2 additions & 11 deletions packages/exceptions/source/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,8 @@ export class TransactionPoolFullError extends PoolError {
}

export class TransactionFailedToPreverifyError extends PoolError {
public readonly error: Error;

public constructor(transaction: Contracts.Crypto.Transaction, error: Error) {
super(`tx ${transaction.hash} cannot be preverified: ${error.message}`, "ERR_PREVERIFY");
this.error = error;
public constructor(transaction: Contracts.Crypto.Transaction, reason: string) {
super(`tx ${transaction.hash} cannot be preverified: ${reason}`, "ERR_PREVERIFY");
}
}

Expand All @@ -83,12 +80,6 @@ export class TransactionFailedToApplyError extends PoolError {
}
}

export class TransactionFailedToVerifyError extends PoolError {
public constructor(transaction: Contracts.Crypto.Transaction) {
super(`tx ${transaction.hash} didn't pass verification`, "ERR_BAD_DATA");
}
}

export class TransactionFromWrongNetworkError extends PoolError {
public currentNetwork: number;

Expand Down
5 changes: 0 additions & 5 deletions packages/processor/source/transaction-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { Contracts } from "@mainsail/contracts";
import { formatCurrency } from "@mainsail/blockchain-utils";
import { Identifiers } from "@mainsail/constants";
import { inject, injectable, tagged } from "@mainsail/container";
import { InvalidSignatureError } from "@mainsail/exceptions";

@injectable()
export class TransactionProcessor implements Contracts.Processor.TransactionProcessor {
Expand Down Expand Up @@ -52,10 +51,6 @@ export class TransactionProcessor implements Contracts.Processor.TransactionProc
},
};

if (!(await this.transactionHandler.verify(transaction))) {
throw new InvalidSignatureError();
}

const receipt = await this.transactionHandler.apply(transactionHandlerContext, transaction);

const feeConsumed = this.feeCalculator.calculateConsumed(transaction.gasPrice, receipt.gasUsed);
Expand Down
2 changes: 0 additions & 2 deletions packages/transaction-pool-service/source/actions/index.ts

This file was deleted.

This file was deleted.

This file was deleted.

8 changes: 0 additions & 8 deletions packages/transaction-pool-service/source/errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,6 @@ describe<{
assert.equal(error.message, `tx ${context.transaction.hash} cannot be applied: Something went horribly wrong`);
});

it("TransactionFailedToVerifyError", (context) => {
const error = new Exceptions.TransactionFailedToVerifyError(context.transaction);

assert.instance(error, Exceptions.PoolError);
assert.equal(error.type, "ERR_BAD_DATA");
assert.equal(error.message, `tx ${context.transaction.hash} didn't pass verification`);
});

it("TransactionFromWrongNetworkError", (context) => {
const error = new Exceptions.TransactionFromWrongNetworkError(context.transaction, 23);

Expand Down
1 change: 0 additions & 1 deletion packages/transaction-pool-service/source/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from "./actions/index.js";
export * from "./mempool.js";
export * from "./processor.js";
export * from "./query.js";
Expand Down
14 changes: 0 additions & 14 deletions packages/transaction-pool-service/source/processor.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Container } from "@mainsail/container";
import { Identifiers } from "@mainsail/constants";
import * as Exceptions from "@mainsail/exceptions";
import { Configuration } from "@mainsail/crypto-config";

import crypto from "../../core/bin/config/devnet/core/crypto.json";
import { describe } from "@mainsail/test-runner";
import { Processor } from "./processor";

Expand All @@ -15,7 +13,6 @@ describe<{
transaction1: any;
transaction2: any;
factory: any;
blockSerializer: any;
}>("Processor", ({ it, assert, beforeAll, stub, spy }) => {
beforeAll((context) => {
context.pool = {
Expand All @@ -24,32 +21,21 @@ describe<{

context.extensions = [{ throwIfCannotBroadcast: () => {} }, { throwIfCannotBroadcast: () => {} }];

context.broadcaster = {
broadcastTransactions: () => Promise.resolve(),
};

context.factory = {
fromBytes: (bytes) => ({}),
fromJson: (tx) => tx,
};

context.blockSerializer = {
headerSize: () => 152,
};
context.broadcaster = {
broadcastTransactions: async () => {},
};

context.container = new Container();
context.container.bind(Identifiers.Cryptography.Block.Serializer).toConstantValue(context.blockSerializer);
context.container.bind(Identifiers.Cryptography.Configuration).to(Configuration).inSingletonScope();
context.container.get<Configuration>(Identifiers.Cryptography.Configuration).setConfig(crypto);

context.container.bind(Identifiers.TransactionPool.ProcessorExtension).toConstantValue(context.extensions[0]);
context.container.bind(Identifiers.TransactionPool.ProcessorExtension).toConstantValue(context.extensions[1]);
context.container.bind(Identifiers.TransactionPool.Service).toConstantValue(context.pool);
context.container.bind(Identifiers.Cryptography.Transaction.Factory).toConstantValue(context.factory);
context.container.bind(Identifiers.Cryptography.Transaction.Deserializer).toConstantValue({});
context.container.bind(Identifiers.TransactionPool.Broadcaster).toConstantValue(context.broadcaster);
context.container.bind(Identifiers.Services.Log.Service).toConstantValue({
error: () => {},
Expand Down
27 changes: 4 additions & 23 deletions packages/transaction-pool-service/source/sender-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ import {
InsufficientBalanceError,
TransactionExceedsMaximumByteSizeError,
TransactionFailedToApplyError,
TransactionFailedToVerifyError,
TransactionFromWrongNetworkError,
UnexpectedNonceError,
} from "@mainsail/exceptions";
import { Services } from "@mainsail/kernel";
import { Wallets } from "@mainsail/state";

@injectable()
Expand All @@ -32,9 +30,6 @@ export class SenderState implements Contracts.TransactionPool.SenderState {
@inject(Identifiers.Transaction.Handler)
private readonly transactionHandler!: Contracts.Transactions.TransactionHandler;

@inject(Identifiers.Services.Trigger.Service)
private readonly triggers!: Services.Triggers.Triggers;

@inject(Identifiers.BlockchainUtils.FeeCalculator)
private readonly feeCalculator!: Contracts.BlockchainUtils.FeeCalculator;

Expand Down Expand Up @@ -118,24 +113,10 @@ export class SenderState implements Contracts.TransactionPool.SenderState {
throw new InsufficientBalanceError();
}

if (
await this.triggers.call("verifyTransaction", {
handler: this.transactionHandler,
transaction,
})
) {
try {
await this.triggers.call("throwIfCannotBeApplied", {
evm: this.evm,
handler: this.transactionHandler,
sender: this.#wallet,
transaction,
});
} catch (error) {
throw new TransactionFailedToApplyError(transaction, error);
}
} else {
throw new TransactionFailedToVerifyError(transaction);
try {
await this.transactionHandler.throwIfCannotBeApplied(transaction, this.#wallet, this.evm);
} catch (error) {
throw new TransactionFailedToApplyError(transaction, error);
}
}
}
14 changes: 1 addition & 13 deletions packages/transaction-pool-service/source/service-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import type { Contracts } from "@mainsail/contracts";

import { Identifiers } from "@mainsail/constants";
import { injectable } from "@mainsail/container";
import { Providers, Services } from "@mainsail/kernel";
import { Providers } from "@mainsail/kernel";
import Joi from "joi";

import { ThrowIfCannotBeAppliedAction, VerifyTransactionAction } from "./actions/index.js";
import { Mempool } from "./mempool.js";
import { Processor } from "./processor.js";
import { Query } from "./query.js";
Expand All @@ -19,7 +18,6 @@ import { Storage } from "./storage.js";
export class ServiceProvider extends Providers.ServiceProvider {
public async register(): Promise<void> {
this.#registerServices();
this.#registerActions();
}

public async boot(): Promise<void> {
Expand Down Expand Up @@ -67,14 +65,4 @@ export class ServiceProvider extends Providers.ServiceProvider {
this.app.bind(Identifiers.TransactionPool.Storage).to(Storage).inSingletonScope();
this.app.bind(Identifiers.TransactionPool.Selector).to(Selector).inSingletonScope();
}

#registerActions(): void {
this.app
.get<Services.Triggers.Triggers>(Identifiers.Services.Trigger.Service)
.bind("verifyTransaction", this.app.resolve(VerifyTransactionAction));

this.app
.get<Services.Triggers.Triggers>(Identifiers.Services.Trigger.Service)
.bind("throwIfCannotBeApplied", this.app.resolve(ThrowIfCannotBeAppliedAction));
}
}
3 changes: 1 addition & 2 deletions packages/transactions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@
"@mainsail/constants": "workspace:*",
"@mainsail/container": "workspace:*",
"@mainsail/exceptions": "workspace:*",
"@mainsail/kernel": "workspace:*",
"@mainsail/utils": "workspace:*"
"@mainsail/kernel": "workspace:*"
},
"devDependencies": {
"@mainsail/contracts": "workspace:*",
Expand Down
2 changes: 0 additions & 2 deletions packages/transactions/source/handlers/index.ts

This file was deleted.

Loading
Loading