Skip to content

Commit

Permalink
feat: add ipAddressHbarSpendingPlan
Browse files Browse the repository at this point in the history
Signed-off-by: Ivo Yankov <[email protected]>
  • Loading branch information
Ivo-Yankov committed Aug 30, 2024
1 parent 1fc40e3 commit 9bd9f0b
Show file tree
Hide file tree
Showing 6 changed files with 451 additions and 81 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
*
* Hedera JSON RPC Relay
*
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

import { IIPAddressHbarSpendingPlan } from '../../types/hbarLimiter/ipAddressHbarSpendingPlan';

export class IPAddressHbarSpendingPlan implements IIPAddressHbarSpendingPlan {
ipAddress: string;
planId: string;

constructor(data: IIPAddressHbarSpendingPlan) {
this.ipAddress = data.ipAddress;
this.planId = data.planId;

Check warning on line 29 in packages/relay/src/lib/db/entities/hbarLimiter/ipAddressHbarSpendingPlan.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/db/entities/hbarLimiter/ipAddressHbarSpendingPlan.ts#L28-L29

Added lines #L28 - L29 were not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
*
* Hedera JSON RPC Relay
*
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

import { CacheService } from '../../../services/cacheService/cacheService';
import { Logger } from 'pino';
import { IIPAddressHbarSpendingPlan } from '../../types/hbarLimiter/ipAddressHbarSpendingPlan';
import { IPAddressHbarSpendingPlanNotFoundError } from '../../types/hbarLimiter/errors';
import { IPAddressHbarSpendingPlan } from '../../entities/hbarLimiter/ipAddressHbarSpendingPlan';

export class IPAddressHbarSpendingPlanRepository {
private readonly collectionKey = 'ipAddressHbarSpendingPlan';
private readonly threeMonthsInMillis = 90 * 24 * 60 * 60 * 1000;

Check warning on line 29 in packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts#L28-L29

Added lines #L28 - L29 were not covered by tests

/**
* The cache service used for storing data.
* @private
*/
private readonly cache: CacheService;

/**
* The logger used for logging all output from this class.
* @private
*/
private readonly logger: Logger;

constructor(cache: CacheService, logger: Logger) {
this.cache = cache;
this.logger = logger;

Check warning on line 45 in packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts#L44-L45

Added lines #L44 - L45 were not covered by tests
}

/**
* Finds an {@link IPAddressHbarSpendingPlan} for an IP address.
*
* @param {string} ipAddress - The IP address to search for.
* @returns {Promise<IPAddressHbarSpendingPlan>} - The associated plan for the IP address.
*/
async findByAddress(ipAddress: string): Promise<IPAddressHbarSpendingPlan> {
const key = this.getKey(ipAddress);
const addressPlan = await this.cache.getAsync<IIPAddressHbarSpendingPlan>(key, 'findByAddress');

Check warning on line 56 in packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts#L55-L56

Added lines #L55 - L56 were not covered by tests
if (!addressPlan) {
throw new IPAddressHbarSpendingPlanNotFoundError(ipAddress);

Check warning on line 58 in packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts#L58

Added line #L58 was not covered by tests
}
this.logger.trace(`Retrieved IPAddressHbarSpendingPlan with address ${ipAddress}`);
return new IPAddressHbarSpendingPlan(addressPlan);

Check warning on line 61 in packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts#L60-L61

Added lines #L60 - L61 were not covered by tests
}

/**
* Saves an {@link IPAddressHbarSpendingPlan} to the cache, linking the plan to the IP address.
*
* @param {IIPAddressHbarSpendingPlan} addressPlan - The plan to save.
* @returns {Promise<void>} - A promise that resolves when the IP address is linked to the plan.
*/
async save(addressPlan: IIPAddressHbarSpendingPlan): Promise<void> {
const key = this.getKey(addressPlan.ipAddress);
await this.cache.set(key, addressPlan, 'save', this.threeMonthsInMillis);
this.logger.trace(`Saved IPAddressHbarSpendingPlan with address ${addressPlan.ipAddress}`);

Check warning on line 73 in packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts#L71-L73

Added lines #L71 - L73 were not covered by tests
}

/**
* Deletes an {@link IPAddressHbarSpendingPlan} from the cache, unlinking the plan from the IP address.
*
* @param {string} ipAddress - The IP address to unlink the plan from.
* @returns {Promise<void>} - A promise that resolves when the IP address is unlinked from the plan.
*/
async delete(ipAddress: string): Promise<void> {
const key = this.getKey(ipAddress);
await this.cache.delete(key, 'delete');
this.logger.trace(`Deleted IPAddressHbarSpendingPlan with address ${ipAddress}`);

Check warning on line 85 in packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts#L83-L85

Added lines #L83 - L85 were not covered by tests
}

/**
* Gets the cache key for an {@link IPAddressHbarSpendingPlan}.
*
* @param {string} ipAddress - The IP address to get the key for.
* @private
*/
private getKey(ipAddress: string): string {
return `${this.collectionKey}:${ipAddress}`;

Check warning on line 95 in packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository.ts#L95

Added line #L95 was not covered by tests
}
}
7 changes: 7 additions & 0 deletions packages/relay/src/lib/db/types/hbarLimiter/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,10 @@ export class EthAddressHbarSpendingPlanNotFoundError extends Error {
this.name = 'EthAddressHbarSpendingPlanNotFoundError';
}
}

export class IPAddressHbarSpendingPlanNotFoundError extends Error {
constructor(ipAddress: string) {
super(`IPAddressHbarSpendingPlan with address ${ipAddress} not found`);
this.name = 'IPAddressHbarSpendingPlanNotFoundError';

Check warning on line 45 in packages/relay/src/lib/db/types/hbarLimiter/errors.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/db/types/hbarLimiter/errors.ts#L44-L45

Added lines #L44 - L45 were not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
*
* Hedera JSON RPC Relay
*
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

export interface IIPAddressHbarSpendingPlan {
ipAddress: string;
planId: string;
}
22 changes: 19 additions & 3 deletions packages/relay/src/lib/services/hbarLimitService/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import { IHbarLimitService } from './IHbarLimitService';
import { HbarSpendingPlanRepository } from '../../db/repositories/hbarLimiter/hbarSpendingPlanRepository';
import { EthAddressHbarSpendingPlanRepository } from '../../db/repositories/hbarLimiter/ethAddressHbarSpendingPlanRepository';
import { IPAddressHbarSpendingPlanRepository } from '../../db/repositories/hbarLimiter/ipAddressHbarSpendingPlanRepository';
import { IDetailedHbarSpendingPlan } from '../../db/types/hbarLimiter/hbarSpendingPlan';
import { SubscriptionType } from '../../db/types/hbarLimiter/subscriptionType';
import { Logger } from 'pino';
Expand All @@ -37,6 +38,7 @@ export class HbarLimitService implements IHbarLimitService {
constructor(
private readonly hbarSpendingPlanRepository: HbarSpendingPlanRepository,
private readonly ethAddressHbarSpendingPlanRepository: EthAddressHbarSpendingPlanRepository,
private readonly ipAddressHbarSpendingPlanRepository: IPAddressHbarSpendingPlanRepository,

Check warning on line 41 in packages/relay/src/lib/services/hbarLimitService/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/services/hbarLimitService/index.ts#L41

Added line #L41 was not covered by tests
private readonly logger: Logger,
) {}

Expand Down Expand Up @@ -95,7 +97,11 @@ export class HbarLimitService implements IHbarLimitService {
}
}
if (ipAddress) {
// TODO: Implement this with https://github.com/hashgraph/hedera-json-rpc-relay/issues/2888
try {
return await this.getSpendingPlanByIPAddress(ipAddress);

Check warning on line 101 in packages/relay/src/lib/services/hbarLimitService/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/services/hbarLimitService/index.ts#L100-L101

Added lines #L100 - L101 were not covered by tests
} catch (error) {
this.logger.warn(error, `Failed to get spending plan for IP address '${ipAddress}'`);

Check warning on line 103 in packages/relay/src/lib/services/hbarLimitService/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/services/hbarLimitService/index.ts#L103

Added line #L103 was not covered by tests
}
}
return null;
}
Expand All @@ -111,6 +117,17 @@ export class HbarLimitService implements IHbarLimitService {
return this.hbarSpendingPlanRepository.findByIdWithDetails(ethAddressHbarSpendingPlan.planId);
}

/**
* Gets the spending plan for the given IP address.
* @param {string} ipAddress - The IP address to get the spending plan for.
* @returns {Promise<IDetailedHbarSpendingPlan>} - A promise that resolves with the spending plan.
* @private
*/
private async getSpendingPlanByIPAddress(ipAddress: string): Promise<IDetailedHbarSpendingPlan> {
const ipAddressHbarSpendingPlan = await this.ipAddressHbarSpendingPlanRepository.findByAddress(ipAddress);
return this.hbarSpendingPlanRepository.findByIdWithDetails(ipAddressHbarSpendingPlan.planId);

Check warning on line 128 in packages/relay/src/lib/services/hbarLimitService/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/services/hbarLimitService/index.ts#L127-L128

Added lines #L127 - L128 were not covered by tests
}

/**
* Creates a basic spending plan for the given eth address.
* @param {string} ethAddress - The eth address to create the spending plan for.
Expand All @@ -128,8 +145,7 @@ export class HbarLimitService implements IHbarLimitService {
await this.ethAddressHbarSpendingPlanRepository.save({ ethAddress, planId: spendingPlan.id });
} else if (ipAddress) {
this.logger.trace(`Linking spending plan with ID ${spendingPlan.id} to ip address ${ipAddress}`);
// TODO: Implement this with https://github.com/hashgraph/hedera-json-rpc-relay/issues/2888
// await this.ipAddressHbarSpendingPlanRepository.save({ ipAddress, planId: spendingPlan.id });
await this.ipAddressHbarSpendingPlanRepository.save({ ipAddress, planId: spendingPlan.id });

Check warning on line 148 in packages/relay/src/lib/services/hbarLimitService/index.ts

View check run for this annotation

Codecov / codecov/patch

packages/relay/src/lib/services/hbarLimitService/index.ts#L148

Added line #L148 was not covered by tests
}
return spendingPlan;
}
Expand Down
Loading

0 comments on commit 9bd9f0b

Please sign in to comment.