Skip to content

Commit

Permalink
fix(crypto-transaction): check and report schema error during builder…
Browse files Browse the repository at this point in the history
… call (#680)

* add error reason to exception

* check error on verify result

* make signatures optional

* use AcceptAnyTransactionVerifier for test builders

* style: resolve style guide violations

---------

Co-authored-by: oXtxNt9U <[email protected]>
  • Loading branch information
oXtxNt9U and oXtxNt9U authored Aug 26, 2024
1 parent f0fc7ae commit a7c6a97
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 12 deletions.
4 changes: 2 additions & 2 deletions packages/contracts/source/exceptions/validation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { InvalidArgumentException } from "./logic.js";

export class ValidationFailed extends InvalidArgumentException {
public constructor() {
super("The given data was invalid.");
public constructor(error?: string) {
super(`The given data was invalid: ${error}`);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,6 @@ describe<{
0,
BigNumber.ZERO,
"test",
null,
undefined,
{},
];
for (const value of invalidValues) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class MultiSignatureRegistrationTransaction extends Transaction {
},
type: { transactionType: Contracts.Crypto.TransactionType.MultiSignature },
},
required: ["asset", "signatures"],
required: ["asset"],
});
}

Expand Down
5 changes: 3 additions & 2 deletions packages/crypto-transaction/source/builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,9 @@ export abstract class TransactionBuilder<TBuilder extends TransactionBuilder<TBu
}

const data = this.#getSigningObject();
if (!(await this.verifier.verifySchema(data, false))) {
throw new Exceptions.ValidationFailed();
const { error } = await this.verifier.verifySchema(data, false);
if (error) {
throw new Exceptions.ValidationFailed(error);
}

this.data.signature = await this.signer.sign(data, keys);
Expand Down
8 changes: 8 additions & 0 deletions packages/test-transaction-builders/source/multi-payments.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Verifier } from "@mainsail/crypto-transaction";
import { MultiPaymentBuilder } from "@mainsail/crypto-transaction-multi-payment";
import { BigNumber } from "@mainsail/utils";

import { Context, MultiPaymentOptions } from "./types.js";
import { buildSignedTransaction, getAddressByPublicKey, getRandomColdWallet, getRandomFundedWallet } from "./utils.js";
import { AcceptAnyTransactionVerifier } from "./verifier.js";

export const makeMultiPayment = async (
context: Context,
options: MultiPaymentOptions = {},
): Promise<Contracts.Crypto.Transaction> => {
// !! Overwrite verifier to accept invalid schema data
context.sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(AcceptAnyTransactionVerifier);

const { sandbox, wallets } = context;
const { app } = sandbox;

Expand Down Expand Up @@ -39,6 +44,9 @@ export const makeMultiPayment = async (
app.get<Contracts.Crypto.Configuration>(Identifiers.Cryptography.Configuration).getMilestone().multiPaymentLimit =
originalMultiPaymentLimit;

// !! Reset
sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(Verifier);

return buildSignedTransaction(sandbox, builder, sender, options);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { Contracts } from "@mainsail/contracts";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Verifier } from "@mainsail/crypto-transaction";
import { MultiSignatureBuilder } from "@mainsail/crypto-transaction-multi-signature-registration";
import { BigNumber } from "@mainsail/utils";

import { Context, MultiPaymentOptions, MultiSignatureOptions } from "./types.js";
import { buildSignedTransaction, getRandomColdWallet, getRandomFundedWallet, getRandomSignature } from "./utils.js";
import { AcceptAnyTransactionVerifier } from "./verifier.js";

export const makeMultiSignatureRegistration = async (
context: Context,
options: MultiSignatureOptions,
): Promise<Contracts.Crypto.Transaction> => {
// !! Overwrite verifier to accept invalid schema data
context.sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(AcceptAnyTransactionVerifier);

const { sandbox, wallets } = context;
const { app } = sandbox;

Expand Down Expand Up @@ -39,6 +44,9 @@ export const makeMultiSignatureRegistration = async (
}
}

// !! Reset
sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(Verifier);

return buildSignedTransaction(sandbox, builder, sender, { ...options, participantSignatures });
};

Expand Down
8 changes: 8 additions & 0 deletions packages/test-transaction-builders/source/transfers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Verifier } from "@mainsail/crypto-transaction";
import { TransferBuilder } from "@mainsail/crypto-transaction-transfer";
import { BigNumber } from "@mainsail/utils";

Expand All @@ -10,11 +11,15 @@ import {
getRandomColdWallet,
getRandomFundedWallet,
} from "./utils.js";
import { AcceptAnyTransactionVerifier } from "./verifier.js";

export const makeTransfer = async (
context: Context,
options: TransferOptions = {},
): Promise<Contracts.Crypto.Transaction> => {
// !! Overwrite verifier to accept invalid schema data
context.sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(AcceptAnyTransactionVerifier);

const { sandbox, wallets } = context;
const { app } = sandbox;

Expand All @@ -33,6 +38,9 @@ export const makeTransfer = async (
.recipientId(recipient)
.amount(BigNumber.make(amount).toFixed());

// !! Reset
sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(Verifier);

return buildSignedTransaction(sandbox, builder, sender, options);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { Contracts } from "@mainsail/contracts";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Verifier } from "@mainsail/crypto-transaction";
import { UsernameRegistrationBuilder } from "@mainsail/crypto-transaction-username-registration";
import { BigNumber } from "@mainsail/utils";

import { Context, UsernameRegistrationOptions } from "./types.js";
import { makeUsernameResignation } from "./username-resignations.js";
import { buildSignedTransaction, getRandomFundedWallet, getRandomUsername } from "./utils.js";
import { AcceptAnyTransactionVerifier } from "./verifier.js";

export const makeUsernameRegistration = async (
context: Context,
options: UsernameRegistrationOptions = {},
): Promise<Contracts.Crypto.Transaction> => {
// !! Overwrite verifier to accept invalid schema data
context.sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(AcceptAnyTransactionVerifier);

const { sandbox, wallets } = context;
const { app } = sandbox;

Expand All @@ -21,6 +26,9 @@ export const makeUsernameRegistration = async (

const builder = app.resolve(UsernameRegistrationBuilder).fee(BigNumber.make(fee).toFixed()).usernameAsset(username);

// !! Reset
sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(Verifier);

return buildSignedTransaction(sandbox, builder, sender, options);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { Contracts } from "@mainsail/contracts";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Verifier } from "@mainsail/crypto-transaction";
import { UsernameResignationBuilder } from "@mainsail/crypto-transaction-username-resignation";
import { BigNumber } from "@mainsail/utils";

import { Context, UsernameResignationOptions } from "./types.js";
import { makeUsernameRegistration } from "./username-registrations.js";
import { buildSignedTransaction, getRandomFundedWallet } from "./utils.js";
import { AcceptAnyTransactionVerifier } from "./verifier.js";

export const makeUsernameResignation = async (
context: Context,
options: UsernameResignationOptions = {},
): Promise<Contracts.Crypto.Transaction> => {
// !! Overwrite verifier to accept invalid schema data
context.sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(AcceptAnyTransactionVerifier);

const { sandbox, wallets } = context;
const { app } = sandbox;

Expand All @@ -20,6 +25,9 @@ export const makeUsernameResignation = async (

const builder = app.resolve(UsernameResignationBuilder).fee(BigNumber.make(fee).toFixed());

// !! Reset
sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(Verifier);

return buildSignedTransaction(sandbox, builder, sender, options);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Contracts } from "@mainsail/contracts";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Verifier } from "@mainsail/crypto-transaction";
import { ValidatorRegistrationBuilder } from "@mainsail/crypto-transaction-validator-registration";
import { BigNumber } from "@mainsail/utils";

Expand All @@ -12,11 +13,15 @@ import {
getRandomConsensusKeyPair,
getRandomFundedWallet,
} from "./utils.js";
import { AcceptAnyTransactionVerifier } from "./verifier.js";

export const makeValidatorRegistration = async (
context: Context,
options: ValidatorRegistrationOptions = {},
): Promise<Contracts.Crypto.Transaction> => {
// !! Overwrite verifier to accept invalid schema data
context.sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(AcceptAnyTransactionVerifier);

const { sandbox, wallets } = context;
const { app } = sandbox;

Expand All @@ -32,6 +37,9 @@ export const makeValidatorRegistration = async (
.fee(BigNumber.make(fee).toFixed())
.publicKeyAsset(validatorPublicKey);

// !! Reset
sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(Verifier);

return buildSignedTransaction(sandbox, builder, sender, options);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { Contracts } from "@mainsail/contracts";
import { Contracts, Identifiers } from "@mainsail/contracts";
import { Verifier } from "@mainsail/crypto-transaction";
import { ValidatorResignationBuilder } from "@mainsail/crypto-transaction-validator-resignation";
import { BigNumber } from "@mainsail/utils";

import { Context, ValidatorResignationOptions } from "./types.js";
import { buildSignedTransaction, getRandomFundedWallet } from "./utils.js";
import { makeValidatorRegistration } from "./validator-registrations.js";
import { AcceptAnyTransactionVerifier } from "./verifier.js";

export const makeValidatorResignation = async (
context: Context,
options: ValidatorResignationOptions = {},
): Promise<Contracts.Crypto.Transaction> => {
// !! Overwrite verifier to accept invalid schema data
context.sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(AcceptAnyTransactionVerifier);

const { sandbox, wallets } = context;
const { app } = sandbox;

Expand All @@ -21,6 +26,9 @@ export const makeValidatorResignation = async (

const builder = app.resolve(ValidatorResignationBuilder).fee(BigNumber.make(fee).toFixed());

// !! Reset
sandbox.app.rebind(Identifiers.Cryptography.Transaction.Verifier).to(Verifier);

return buildSignedTransaction(sandbox, builder, sender, options);
};

Expand Down

0 comments on commit a7c6a97

Please sign in to comment.