Skip to content

Commit

Permalink
Merge pull request #213 from HathorNetwork/release-candidate
Browse files Browse the repository at this point in the history
Release v1.7.0
  • Loading branch information
andreabadesso authored Feb 12, 2025
2 parents f16e1a7 + 57e9fba commit 6412591
Show file tree
Hide file tree
Showing 11 changed files with 446 additions and 45 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hathor-wallet-service",
"version": "1.6.4",
"version": "1.7.0",
"workspaces": [
"packages/common",
"packages/daemon",
Expand Down
87 changes: 80 additions & 7 deletions packages/daemon/__tests__/guards/guards.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Context, Event, FullNodeEventTypes } from '../../src/types';
import { Context, Event, FullNodeEventTypes, FullNodeEvent, StandardFullNodeEvent } from '../../src/types';
import {
metadataIgnore,
metadataVoided,
Expand All @@ -12,6 +12,7 @@ import {
voided,
unchanged,
invalidNetwork,
reorgStarted,
} from '../../src/guards';
import { EventTypes } from '../../src/types';

Expand Down Expand Up @@ -45,7 +46,7 @@ const mockContext: Context = {
txCache: TxCache,
};

const generateFullNodeEvent = (type: FullNodeEventTypes, data = {} as any): Event => ({
const generateStandardFullNodeEvent = (type: Exclude<FullNodeEventTypes, FullNodeEventTypes.REORG_STARTED>, data = {} as any): Event => ({
type: EventTypes.FULLNODE_EVENT,
event: {
type: 'EVENT',
Expand All @@ -62,15 +63,79 @@ const generateFullNodeEvent = (type: FullNodeEventTypes, data = {} as any): Even
},
});

const generateMetadataDecidedEvent = (type: string): Event => ({
type: EventTypes.METADATA_DECIDED,
const generateReorgStartedEvent = (data = {
reorg_size: 1,
previous_best_block: 'prev',
new_best_block: 'new',
common_block: 'common',
}): Event => ({
type: EventTypes.FULLNODE_EVENT,
event: {
type,
// @ts-ignore
originalEvent: {} as any,
type: 'EVENT',
network: 'mainnet',
peer_id: '',
stream_id: '',
event: {
id: 0,
timestamp: 0,
type: FullNodeEventTypes.REORG_STARTED,
data,
group_id: 1,
},
latest_event_id: 0,
},
});

const generateFullNodeEvent = (type: FullNodeEventTypes, data = {} as any): Event => {
if (type === FullNodeEventTypes.REORG_STARTED) {
return generateReorgStartedEvent(data);
}
return generateStandardFullNodeEvent(type, data);
};

const generateMetadataDecidedEvent = (type: 'TX_VOIDED' | 'TX_UNVOIDED' | 'TX_NEW' | 'TX_FIRST_BLOCK' | 'IGNORE'): Event => {
const fullNodeEvent: StandardFullNodeEvent = {
stream_id: '',
peer_id: '',
network: 'mainnet',
type: 'EVENT',
latest_event_id: 0,
event: {
id: 0,
timestamp: 0,
type: FullNodeEventTypes.VERTEX_METADATA_CHANGED,
data: {
hash: 'hash',
timestamp: 0,
version: 1,
weight: 1,
nonce: 1,
inputs: [],
outputs: [],
parents: [],
tokens: [],
token_name: null,
token_symbol: null,
signal_bits: 1,
metadata: {
hash: 'hash',
voided_by: [],
first_block: null,
height: 1,
},
},
},
};

return {
type: EventTypes.METADATA_DECIDED,
event: {
type,
originalEvent: fullNodeEvent,
},
};
};

describe('metadata decided tests', () => {
test('metadataIgnore', async () => {
expect(metadataIgnore(mockContext, generateMetadataDecidedEvent('IGNORE'))).toBe(true);
Expand Down Expand Up @@ -171,6 +236,14 @@ describe('fullnode event guards', () => {
// Any event other than FULLNODE_EVENT should return false
expect(() => unchanged(mockContext, generateMetadataDecidedEvent('TX_NEW'))).toThrow('Invalid event type on unchanged guard: METADATA_DECIDED');
});

test('reorgStarted', () => {
expect(reorgStarted(mockContext, generateFullNodeEvent(FullNodeEventTypes.REORG_STARTED))).toBe(true);
expect(reorgStarted(mockContext, generateFullNodeEvent(FullNodeEventTypes.VERTEX_METADATA_CHANGED))).toBe(false);

// Any event other than FULLNODE_EVENT should throw
expect(() => reorgStarted(mockContext, generateMetadataDecidedEvent('TX_NEW'))).toThrow('Invalid event type on reorgStarted guard: METADATA_DECIDED');
});
});

describe('fullnode validation guards', () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/daemon/__tests__/machines/SyncMachine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ describe('Event handling', () => {
expect(currentState.matches(`${SYNC_MACHINE_STATES.CONNECTED}.${CONNECTED_STATES.handlingUnhandledEvent}`)).toBeTruthy();
});

it('should ignore REORG_STARTED event but still send ack', () => {
it('should handle REORG_STARTED event', () => {
const MockedFetchMachine = SyncMachine.withConfig({
guards: {
invalidPeerId: () => false,
Expand All @@ -535,6 +535,6 @@ describe('Event handling', () => {
event: REORG_STARTED as unknown as FullNodeEvent,
});

expect(currentState.matches(`${SYNC_MACHINE_STATES.CONNECTED}.${CONNECTED_STATES.handlingUnhandledEvent}`)).toBeTruthy();
expect(currentState.matches(`${SYNC_MACHINE_STATES.CONNECTED}.${CONNECTED_STATES.handlingReorgStarted}`)).toBeTruthy();
});
});
209 changes: 202 additions & 7 deletions packages/daemon/__tests__/services/services.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
handleVoidedTx,
handleVertexAccepted,
metadataDiff,
handleReorgStarted,
} from '../../src/services';
import logger from '../../src/logger';
import {
Expand All @@ -42,13 +43,10 @@ import {
generateAddresses,
} from '../../src/utils';
import getConfig from '../../src/config';

jest.mock('../../src/config', () => {
return {
__esModule: true, // This property is needed for mocking a default export
default: jest.fn(() => ({})),
};
});
import { addAlert, Severity } from '@wallet-service/common';
import { FullNodeEventTypes } from '../../src/types';
import { Context } from '../../src/types';
import { generateFullNodeEvent } from '../utils';

jest.mock('@hathor/wallet-lib');
jest.mock('../../src/logger', () => ({
Expand Down Expand Up @@ -109,6 +107,41 @@ jest.mock('../../src/utils', () => ({
generateAddresses: jest.fn(),
}));

jest.mock('@wallet-service/common', () => {
const addAlertMock = jest.fn();
return {
addAlert: addAlertMock,
Severity: {
INFO: 'INFO',
MINOR: 'MINOR',
MAJOR: 'MAJOR',
CRITICAL: 'CRITICAL',
},
NftUtils: {
shouldInvokeNftHandlerForTx: jest.fn().mockReturnValue(false),
invokeNftHandlerLambda: jest.fn(),
},
};
});

jest.mock('../../src/config', () => {
return {
__esModule: true, // This property is needed for mocking a default export
default: jest.fn(() => ({
REORG_SIZE_INFO: 1,
REORG_SIZE_MINOR: 3,
REORG_SIZE_MAJOR: 5,
REORG_SIZE_CRITICAL: 10,
})),
getConfig: jest.fn(() => ({
REORG_SIZE_INFO: 1,
REORG_SIZE_MINOR: 3,
REORG_SIZE_MAJOR: 5,
REORG_SIZE_CRITICAL: 10,
})),
};
});

beforeEach(() => {
jest.clearAllMocks();
});
Expand Down Expand Up @@ -838,3 +871,165 @@ describe('metadataDiff', () => {
expect(result.type).toBe('TX_UNVOIDED');
});
});

describe('handleReorgStarted', () => {
beforeEach(() => {
(getConfig as jest.Mock).mockReturnValue({
REORG_SIZE_INFO: 1,
REORG_SIZE_MINOR: 3,
REORG_SIZE_MAJOR: 5,
REORG_SIZE_CRITICAL: 10,
});
});

afterEach(() => {
jest.clearAllMocks();
});

it('should add INFO alert when reorg size equals REORG_SIZE_INFO', async () => {
const event = generateFullNodeEvent({
type: FullNodeEventTypes.REORG_STARTED,
data: {
reorg_size: 1,
previous_best_block: 'prev',
new_best_block: 'new',
common_block: 'common',
},
});

// @ts-ignore
await handleReorgStarted({ event } as Context);

expect(addAlert).toHaveBeenCalledWith(
'Reorg Detected',
'A reorg of size 1 has occurred.',
Severity.INFO,
{
reorg_size: 1,
previous_best_block: 'prev',
new_best_block: 'new',
common_block: 'common',
},
expect.anything(),
);
});

it('should add MINOR alert when reorg size is between REORG_SIZE_MINOR and REORG_SIZE_MAJOR', async () => {
const event = generateFullNodeEvent({
type: FullNodeEventTypes.REORG_STARTED,
data: {
reorg_size: 3,
previous_best_block: 'prev',
new_best_block: 'new',
common_block: 'common',
},
});

// @ts-ignore
await handleReorgStarted({ event } as Context);

expect(addAlert).toHaveBeenCalledWith(
'Minor Reorg Detected',
'A minor reorg of size 3 has occurred.',
Severity.MINOR,
{
reorg_size: 3,
previous_best_block: 'prev',
new_best_block: 'new',
common_block: 'common',
},
expect.anything(),
);
});

it('should add MAJOR alert when reorg size is between REORG_SIZE_MAJOR and REORG_SIZE_CRITICAL', async () => {
const event = generateFullNodeEvent({
type: FullNodeEventTypes.REORG_STARTED,
data: {
reorg_size: 7,
previous_best_block: 'prev',
new_best_block: 'new',
common_block: 'common',
},
});

// @ts-ignore
await handleReorgStarted({ event } as Context);

expect(addAlert).toHaveBeenCalledWith(
'Major Reorg Detected',
'A major reorg of size 7 has occurred.',
Severity.MAJOR,
{
reorg_size: 7,
previous_best_block: 'prev',
new_best_block: 'new',
common_block: 'common',
},
expect.anything(),
);
});

it('should add CRITICAL alert when reorg size is greater than REORG_SIZE_CRITICAL', async () => {
const event = generateFullNodeEvent({
type: FullNodeEventTypes.REORG_STARTED,
data: {
reorg_size: 11,
previous_best_block: 'prev',
new_best_block: 'new',
common_block: 'common',
},
});

// @ts-ignore
await handleReorgStarted({ event } as Context);

expect(addAlert).toHaveBeenCalledWith(
'Critical Reorg Detected',
'A critical reorg of size 11 has occurred.',
Severity.CRITICAL,
{
reorg_size: 11,
previous_best_block: 'prev',
new_best_block: 'new',
common_block: 'common',
},
expect.anything(),
);
});

it('should not add alert when reorg size is less than REORG_SIZE_INFO', async () => {
const event = generateFullNodeEvent({
type: FullNodeEventTypes.REORG_STARTED,
data: {
reorg_size: 0,
previous_best_block: 'prev',
new_best_block: 'new',
common_block: 'common',
},
});

// @ts-ignore
await handleReorgStarted({ event } as Context);

expect(addAlert).not.toHaveBeenCalled();
});

it('should throw error when event is missing', async () => {
await expect(handleReorgStarted({} as Context))
.rejects
.toThrow('No event in context');
});

it('should throw error when event type is incorrect', async () => {
const event = generateFullNodeEvent({
type: FullNodeEventTypes.VERTEX_METADATA_CHANGED,
data: {},
});

// @ts-ignore
await expect(handleReorgStarted({ event } as Context))
.rejects
.toThrow('Invalid event type for REORG_STARTED');
});
});
Loading

0 comments on commit 6412591

Please sign in to comment.