Skip to content

Commit

Permalink
Showing 21 changed files with 527 additions and 96 deletions.
18 changes: 18 additions & 0 deletions packages/core/src/utils/assertions/account-assertions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { DATA, assert } from '@vechainfoundation/vechain-sdk-errors';
import { addressUtils } from '../../address';

/**
* Assert if address is valid
*
* @param address - Address to assert
*/
function assertIsAddress(address: string): void {
assert(
addressUtils.isAddress(address),
DATA.INVALID_DATA_TYPE,
'Invalid address. The address must be 20 bytes (a 42 characters hex string with a `0x` prefix.)',
{ address }
);
}

export { assertIsAddress };
32 changes: 32 additions & 0 deletions packages/core/src/utils/assertions/block-assertions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { DATA, assert } from '@vechainfoundation/vechain-sdk-errors';
import { revisionUtils } from '../revision';

/**
* Assert if a given revision is valid.
* A valid revision is a string representing a block number or block id.
*
* @param revision - Revision to assert
*/
function assertIsRevisionForBlock(revision?: string | number): void {
assert(
revision === undefined ||
revision === null ||
revisionUtils.isRevisionBlock(revision),
DATA.INVALID_DATA_TYPE,
'Invalid revision. The revision must be a string representing a block number or block id (also "best" is accepted which represents the best block & "finalized" for the finalized block).',
{ revision }
);
}

function assertIsRevisionForAccount(revision?: string | number): void {
assert(
revision === undefined ||
revision === null ||
revisionUtils.isRevisionAccount(revision),
DATA.INVALID_DATA_TYPE,
'Invalid revision. The revision must be a string representing a block number or block id (also "best" is accepted which represents the best block).',
{ revision }
);
}

export { assertIsRevisionForBlock, assertIsRevisionForAccount };
3 changes: 3 additions & 0 deletions packages/core/src/utils/assertions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './account-assertions';
export * from './block-assertions';
export * from './transaction-assertions';
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { assert, DATA } from '@vechainfoundation/vechain-sdk-errors';
import { dataUtils } from '@vechainfoundation/vechain-sdk-core';
import {
DATA,
TRANSACTION,
assert
} from '@vechainfoundation/vechain-sdk-errors';
import { dataUtils } from '../data';
import { type Transaction } from '../../transaction';

/**
* Assert if transaction ID is valid
@@ -28,4 +33,20 @@ function assertValidTransactionHead(head?: string): void {
);
}

export { assertValidTransactionID, assertValidTransactionHead };
/**
* Asserts that the given transaction is signed.
* @param tx - The transaction to check.
*
* @throws {InvalidTransactionError} if the transaction is not signed.
*/
const assertIsSignedTransaction = (tx: Transaction): void => {
assert(tx.isSigned, TRANSACTION.NOT_SIGNED, 'Transaction must be signed.', {
tx
});
};

export {
assertValidTransactionID,
assertValidTransactionHead,
assertIsSignedTransaction
};
2 changes: 2 additions & 0 deletions packages/core/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -4,3 +4,5 @@ export * from './data';
export * from './hdnode';
export * from './transaction';
export * from './units';
export * from './revision';
export * from './assertions';
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { dataUtils } from '@vechainfoundation/vechain-sdk-core';
import { dataUtils } from '../data';

/**
* Determines whether the provided revision is a valid for blocks functions.
40 changes: 40 additions & 0 deletions packages/core/tests/utils/assertions/account-assertions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { describe, expect, test } from '@jest/globals';
import { accountAssertionsTests } from './fixture';
import { assertIsAddress } from '../../../src';
import { InvalidDataTypeError } from '@vechainfoundation/vechain-sdk-errors';

/**
* Account assertions
*
* @group unit/utils-assertions
*/
describe('Account assertions', () => {
/**
* Assert is address test suite
*/
describe('assertIsAddress', () => {
/**
* Valid addresses test cases
*/
accountAssertionsTests.assertIsAddress.valid.forEach(({ value }) => {
test(`should not throw error for assertIsAddress of ${value}`, () => {
// Expect assertIsAddress to not throw
expect(() => {
assertIsAddress(value);
}).not.toThrow();
});
});

/**
* Invalid addresses test cases
*/
accountAssertionsTests.assertIsAddress.invalid.forEach(({ value }) => {
test(`hould throw error for assertIsAddress of ${value}`, () => {
// Expect assertIsAddress to throw
expect(() => {
assertIsAddress(value);
}).toThrowError(InvalidDataTypeError);
});
});
});
});
75 changes: 75 additions & 0 deletions packages/core/tests/utils/assertions/block-assertions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { describe, expect, test } from '@jest/globals';
import { blockAssertionsTests } from './fixture';
import {
assertIsRevisionForAccount,
assertIsRevisionForBlock
} from '../../../src';

/**
* Block assertions
*
* @group unit/utils-assertions
*/
describe('Block assertions', () => {
/**
* Assert is valid revision
*/
describe('assertIsRevision', () => {
/**
* Valid account endpoint revisions
*/
blockAssertionsTests.assertIsRevisionForAccount.valid.forEach(
({ value }) => {
test(`should not throw error for assertIsRevision of ${value}`, () => {
expect(() => {
assertIsRevisionForAccount(value);
}).not.toThrow();
});
}
);

/**
* Invalid account endpoint revisions
*/
blockAssertionsTests.assertIsRevisionForAccount.invalid.forEach(
({ value }) => {
test(`should throw error for assertIsRevision of ${value}`, () => {
expect(() => {
assertIsRevisionForAccount(value);
}).toThrow();
});
}
);
});

/**
* Assert is valid block revision
*/
describe('assertIsRevisionForBlock', () => {
/**
* Valid block endpoint revisions
*/
blockAssertionsTests.assertIsRevisionForBlock.valid.forEach(
({ value }) => {
test(`should not throw error for assertIsRevision of ${value}`, () => {
expect(() => {
assertIsRevisionForBlock(value);
}).not.toThrow();
});
}
);

/**
* Invalid block endpoint revisions
*/
blockAssertionsTests.assertIsRevisionForBlock.invalid.forEach(
({ value }) => {
test(`should throw error for assertIsRevision of ${value}`, () => {
expect(() => {
assertIsRevisionForBlock(value);
}).toThrow();
});
}
);
});
});
194 changes: 194 additions & 0 deletions packages/core/tests/utils/assertions/fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import { Transaction, TransactionHandler } from '../../../src';
import { signer, transactions } from '../../transaction/fixture';

/**
* Generates a random buffer of the specified length
*
* @param length - The length of the buffer to generate
* @returns A random buffer of the specified length
*/
const generateRandomBytes = (length: number): Buffer => {
const buffer = Buffer.alloc(length);
for (let i = 0; i < length; i++) {
// Generate a random byte
buffer[i] = Math.floor(Math.random() * 256);
}

return buffer;
};

/**
* Generates a random valid address
*
* @returns A random valid address of 20 bytes
*/
const generateRandomValidAddress = (): string => {
const buffer = generateRandomBytes(20);

return '0x' + buffer.toString('hex');
};

/**
* Generates a random valid transaction ID
*
* @returns A random valid transaction ID of 32 bytes
*/
const generateRandomTransactionID = (): string => {
const buffer = generateRandomBytes(32);

return '0x' + buffer.toString('hex');
};

/**
* Generates a random valid transaction head
*
* @returns - A random valid transaction head of 32 bytes
*/
const generateRandomTransactionHead = (): string => {
return generateRandomTransactionID();
};

/**
* Account assertion tests
*/
const accountAssertionsTests = {
assertIsAddress: {
valid: [
{
value: generateRandomValidAddress()
}
],
invalid: [
{
value: '0x'
},
{
value: '0x0'
}
]
}
};

/**
* Transaction assertion tests
*/
const transactionAssertionsTests = {
assertValidTransactionID: {
valid: [
{
value: generateRandomTransactionID()
}
],
invalid: [
{
value: '0x'
},
{
value: '0x0'
}
]
},
assertValidTransactionHead: {
valid: [
{
value: generateRandomTransactionHead()
},
{
value: undefined
}
],
invalid: [
{
value: '0x'
},
{
value: '0x0'
}
]
},
assertIsSignedTransaction: {
valid: [
{
value: TransactionHandler.sign(
new Transaction({
...transactions.undelegated[0].body
}),
signer.privateKey
)
}
],
invalid: [
{
value: new Transaction({
...transactions.undelegated[0].body
})
}
]
}
};

/**
* Block assertion tests
*/
const blockAssertionsTests = {
assertIsRevisionForAccount: {
valid: [
{
value: '0x542fd'
},
{
value: '100'
},
{
value: 100
},
{
value: 'best'
}
],
invalid: [
{
value: 'invalid-revision'
},
{
value: '0xG8656c6c6f'
},
{
value: 'finalized'
}
]
},
assertIsRevisionForBlock: {
valid: [
{
value: '0x542fd'
},
{
value: '100'
},
{
value: 100
},
{
value: 'best'
},
{
value: 'finalized'
}
],
invalid: [
{
value: 'invalid-revision'
},
{
value: '0xG8656c6c6f'
}
]
}
};

export {
accountAssertionsTests,
transactionAssertionsTests,
blockAssertionsTests
};
114 changes: 114 additions & 0 deletions packages/core/tests/utils/assertions/transaction-assertions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { describe, expect, test } from '@jest/globals';
import { transactionAssertionsTests } from './fixture';
import {
assertIsSignedTransaction,
assertValidTransactionHead,
assertValidTransactionID
} from '../../../src';

/**
* Transaction assertions
*
* @group unit/utils-assertions
*/
describe('Transaction assertions', () => {
/**
* Assert valid transaction ID test suite
*/
describe('assertValidTransactionID', () => {
/**
* Valid transaction IDs test cases
*/
transactionAssertionsTests.assertValidTransactionID.valid.forEach(
({ value }) => {
test(`should not throw error for assertValidTransactionID of ${value}`, () => {
// Expect assertValidTransactionID to not throw
expect(() => {
assertValidTransactionID(value);
}).not.toThrow();
});
}
);

/**
* Invalid transaction IDs test cases
*/
transactionAssertionsTests.assertValidTransactionID.invalid.forEach(
({ value }) => {
test(`should throw error for assertValidTransactionID of ${value}`, () => {
// Expect assertValidTransactionID to throw
expect(() => {
assertValidTransactionID(value);
}).toThrowError();
});
}
);
});

describe('assertValidTransactionHead', () => {
/**
* Valid transaction heads test cases
*/
transactionAssertionsTests.assertValidTransactionHead.valid.forEach(
({ value }) => {
test(`should not throw error for assertValidTransactionHead of ${value}`, () => {
// Expect assertValidTransactionHead to not throw
expect(() => {
assertValidTransactionHead(value);
}).not.toThrow();
});
}
);

/**
* Invalid transaction heads test cases
*/
transactionAssertionsTests.assertValidTransactionHead.invalid.forEach(
({ value }) => {
test(`should throw error for assertValidTransactionHead of ${value}`, () => {
// Expect assertValidTransactionHead to throw
expect(() => {
assertValidTransactionHead(value);
}).toThrowError();
});
}
);
});

/**
* Assert is signed transaction test suite
*/
describe('assertIsSignedTransaction', () => {
/**
* Valid signed transactions test cases
*/
transactionAssertionsTests.assertIsSignedTransaction.valid.forEach(
({ value }) => {
test(`should not throw error for assertIsSignedTransaction of ${JSON.stringify(
value
)}`, () => {
// Expect assertIsSignedTransaction to not throw
expect(() => {
assertIsSignedTransaction(value);
}).not.toThrow();
});
}
);

/**
* Invalid signed transactions test cases
*/
transactionAssertionsTests.assertIsSignedTransaction.invalid.forEach(
({ value }) => {
test(`should throw error for assertIsSignedTransaction of ${JSON.stringify(
value
)}`, () => {
// Expect assertIsSignedTransaction to throw
expect(() => {
assertIsSignedTransaction(value);
}).toThrowError();
});
}
);
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { testAccount } from '../../fixture';

/**
* Test cases for the `isRevisionAccount` function.
*/
@@ -13,7 +11,7 @@ const accountRevisions = [
expected: false
},
{
revision: testAccount,
revision: '0x34123',
expected: true
},
{
@@ -43,7 +41,7 @@ const blockRevisions = [
expected: false
},
{
revision: testAccount,
revision: '0x542fd',
expected: true
},
{
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { revisionUtils } from '../../../src/utils';
import { describe, expect, test } from '@jest/globals';
import { accountRevisions, blockRevisions } from './fixture';
import { revisionUtils } from '../../../src';

/**
* Unit tests for the blockUtils module.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { type Transaction } from '@vechainfoundation/vechain-sdk-core';
import {
type Transaction,
assertIsSignedTransaction
} from '@vechainfoundation/vechain-sdk-core';
import { Poll, type HttpClient } from '../../../utils';
import {
type TransactionReceipt,
TransactionsClient
} from '../../thorest-client';
import { type WaitForTransactionOptions } from './types';
import { assertIsSignedTx } from './helpers';

/**
* The `TransactionsModule` handles transaction related operations and provides
@@ -35,7 +37,7 @@ class TransactionsModule {
* @throws an error if the transaction is not signed.
*/
public async sendTransaction(signedTx: Transaction): Promise<string> {
assertIsSignedTx(signedTx);
assertIsSignedTransaction(signedTx);

const rawTx = `0x${signedTx.encoded.toString('hex')}`;

Original file line number Diff line number Diff line change
@@ -6,8 +6,11 @@ import {
type ResponseStorage,
type AccountInputOptions
} from './types';
import { dataUtils } from '@vechainfoundation/vechain-sdk-core';
import { assertIsAddress, assertIsRevision } from './helpers/assertions';
import {
dataUtils,
assertIsAddress,
assertIsRevisionForAccount
} from '@vechainfoundation/vechain-sdk-core';

/**
* The `AccountClient` class provides methods to interact with account-related endpoints
@@ -37,7 +40,7 @@ class AccountsClient {
): Promise<AccountDetail> {
assertIsAddress(address);

assertIsRevision(options?.revision);
assertIsRevisionForAccount(options?.revision);

return (await this.httpClient.http(
'GET',
@@ -64,7 +67,7 @@ class AccountsClient {
): Promise<string> {
assertIsAddress(address);

assertIsRevision(options?.revision);
assertIsRevisionForAccount(options?.revision);

const result = (await this.httpClient.http(
'GET',
@@ -95,7 +98,7 @@ class AccountsClient {
): Promise<string> {
assertIsAddress(address);

assertIsRevision(options?.revision);
assertIsRevisionForAccount(options?.revision);

// The position represents a slot in the VM storage. Each slot is 32 bytes.
assert(

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { DATA, assert } from '@vechainfoundation/vechain-sdk-errors';
import {
revisionUtils,
buildQuery,
thorest,
type HttpClient
} from '../../../utils';
import { buildQuery, thorest, type HttpClient } from '../../../utils';
import { type BlockDetail, type BlockInputOptions } from './types';
import { assertIsRevisionForBlock } from '@vechainfoundation/vechain-sdk-core';

/**
* The `BlockClient` class provides methods to interact with block-related endpoints
@@ -29,14 +24,7 @@ class BlocksClient {
revision: string | number,
options?: BlockInputOptions
): Promise<BlockDetail | null> {
assert(
revision === undefined ||
revision === null ||
revisionUtils.isRevisionBlock(revision),
DATA.INVALID_DATA_TYPE,
'Invalid revision. The revision must be a string representing a block number or block id.',
{ revision }
);
assertIsRevisionForBlock(revision);

return (await this.httpClient.http(
'GET',
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import {
type HttpClient,
buildQuery,
thorest,
revisionUtils
} from '../../../utils';
import { type HttpClient, buildQuery, thorest } from '../../../utils';
import {
dataUtils,
TransactionHandler
revisionUtils,
TransactionHandler,
assertValidTransactionID,
assertValidTransactionHead
} from '@vechainfoundation/vechain-sdk-core';
import {
type SimulateTransactionClause,
@@ -23,10 +21,6 @@ import {
buildError,
DATA
} from '@vechainfoundation/vechain-sdk-errors';
import {
assertValidTransactionHead,
assertValidTransactionID
} from './helpers/assertions';

/**
* Client for reading and creating transactions
1 change: 0 additions & 1 deletion packages/network/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -2,5 +2,4 @@ export * from './const';
export * from './helpers';
export * from './http';
export * from './poll';
export * from './revision';
export * from './thorest';

1 comment on commit e9580d0

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test Coverage

Summary

Lines Statements Branches Functions
Coverage: 100%
100% (1229/1229) 100% (267/267) 100% (259/259)
Title Tests Skipped Failures Errors Time
core 347 0 💤 0 ❌ 0 🔥 1m 16s ⏱️
network 84 0 💤 0 ❌ 0 🔥 46.542s ⏱️
errors 30 0 💤 0 ❌ 0 🔥 7.986s ⏱️

Please sign in to comment.