Skip to content

Commit fca6a53

Browse files
authored
Add a way to manage environment variables - task 86c43c329 (#5)
* Added config for dig and moved what will not be changedable as constants to the files their are in scope for Signed-off-by: Robert Gogete <gogeterobert@yahoo.com> * Added default for dig path and updated test Signed-off-by: Robert Gogete <gogeterobert@yahoo.com> --------- Signed-off-by: Robert Gogete <gogeterobert@yahoo.com>
1 parent d514c2a commit fca6a53

File tree

9 files changed

+46
-45
lines changed

9 files changed

+46
-45
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,7 @@ dist
274274
# Local databases
275275

276276
**/*.sqlite
277+
278+
# Local dig files
279+
280+
.dig

src/application/services/FileCacheService.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import fs from "fs";
22
import path from "path";
3-
4-
export const DIG_FOLDER_PATH = path.join(process.cwd(), ".dig");
3+
import config from "../../config";
54

65
export class FileCacheService<T> {
76
private cacheDir: string;
87

9-
constructor(relativeFilePath: string, baseDir: string = DIG_FOLDER_PATH) {
10-
this.cacheDir = path.join(baseDir, relativeFilePath);
8+
constructor(relativeFilePath: string) {
9+
this.cacheDir = path.join(config.DIG_FOLDER_PATH, relativeFilePath);
1110
this.ensureDirectoryExists();
1211
}
1312

src/application/services/WalletService.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ import * as bip39 from 'bip39';
33
import { NconfService } from '../../infrastructure/ConfigurationServices/NconfService';
44
import { EncryptionService } from './EncryptionService';
55
import { EncryptedData } from '../types/EncryptedData';
6-
import { MIN_HEIGHT, MIN_HEIGHT_HEADER_HASH, Wallet } from '../types/Wallet';
76
import { Peer, verifySignedMessage } from '@dignetwork/datalayer-driver';
7+
import { Wallet } from '../types/Wallet';
88

9-
export const KEYRING_FILE = 'keyring.json';
10-
export const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
9+
const KEYRING_FILE = 'keyring.json';
1110

1211
export class WalletService {
1312
public static async loadWallet(walletName: string = 'default'): Promise<Wallet> {
@@ -37,8 +36,8 @@ export class WalletService {
3736
return [];
3837
}
3938

40-
const config = await nconfService.getFullConfig();
41-
return Object.keys(config);
39+
const configData = await nconfService.getFullConfig();
40+
return Object.keys(configData);
4241
}
4342

4443
public static async verifyKeyOwnershipSignature(
@@ -58,9 +57,9 @@ export class WalletService {
5857
return BigInt(1000000);
5958
}
6059

61-
public static async isCoinSpendable(peer: Peer, coinId: Buffer): Promise<boolean> {
60+
public static async isCoinSpendable(peer: Peer, coinId: Buffer, lastHeight: number, lastHeaderHash: string): Promise<boolean> {
6261
try {
63-
return await peer.isCoinSpent(coinId, MIN_HEIGHT, Buffer.from(MIN_HEIGHT_HEADER_HASH, 'hex'));
62+
return await peer.isCoinSpent(coinId, lastHeight, Buffer.from(lastHeaderHash, 'hex'));
6463
} catch {
6564
return false;
6665
}

src/application/types/Wallet.ts

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {
2-
Coin,
2+
Coin,
33
getCoinId,
44
masterPublicKeyToFirstPuzzleHash,
55
masterPublicKeyToWalletSyntheticKey,
@@ -13,15 +13,8 @@ import {
1313
import { mnemonicToSeedSync } from 'bip39';
1414
import { PrivateKey } from 'chia-bls';
1515
import { FileCacheService } from '../services/FileCacheService';
16-
import { CACHE_DURATION } from '../services/WalletService';
17-
import path from 'path';
18-
import os from 'os';
1916

20-
export const MIN_HEIGHT = 5777842;
21-
export const MIN_HEIGHT_HEADER_HASH =
22-
"b29a4daac2434fd17a36e15ba1aac5d65012d4a66f99bed0bf2b5342e92e562c";
23-
24-
export const USER_DIR_PATH = path.join(os.homedir(), '.dig');
17+
const COIN_CACHE_DURATION = 600000;
2518

2619
export class Wallet {
2720
private mnemonic: string;
@@ -75,21 +68,18 @@ export class Wallet {
7568
peer: Peer,
7669
coinAmount: bigint,
7770
feeBigInt: bigint,
78-
omitCoins: Coin[] = []
71+
omitCoins: Coin[] = [],
72+
lastHeight: number,
73+
lastHeaderHash: string,
7974
): Promise<Coin[]> {
80-
const cache = new FileCacheService<{ coinId: string; expiry: number }>(
81-
"reserved_coins",
82-
USER_DIR_PATH
83-
);
75+
const cache = new FileCacheService<{ coinId: string; expiry: number }>('reserved_coins');
8476

8577
const ownerPuzzleHash = await this.getOwnerPuzzleHash();
8678

8779
// Define a function to attempt selecting unspent coins
8880
const trySelectCoins = async (): Promise<Coin[]> => {
8981
const now = Date.now();
90-
const omitCoinIds = omitCoins.map((coin) =>
91-
getCoinId(coin).toString("hex")
92-
);
82+
const omitCoinIds = omitCoins.map((coin) => getCoinId(coin).toString('hex'));
9383

9484
// Update omitCoinIds with currently valid reserved coins
9585
const cachedReservedCoins = cache.getCachedKeys();
@@ -107,12 +97,12 @@ export class Wallet {
10797

10898
const coinsResp = await peer.getAllUnspentCoins(
10999
ownerPuzzleHash,
110-
MIN_HEIGHT,
111-
Buffer.from(MIN_HEIGHT_HEADER_HASH, "hex")
100+
lastHeight,
101+
Buffer.from(lastHeaderHash, 'hex'),
112102
);
113103

114104
const unspentCoins = coinsResp.coins.filter(
115-
(coin) => !omitCoinIds.includes(getCoinId(coin).toString("hex"))
105+
(coin) => !omitCoinIds.includes(getCoinId(coin).toString('hex')),
116106
);
117107

118108
const selectedCoins = selectCoins(unspentCoins, feeBigInt + coinAmount);
@@ -142,15 +132,15 @@ export class Wallet {
142132
await new Promise((resolve) => setTimeout(resolve, 10000));
143133
} else {
144134
// No unspent coins and no reserved coins
145-
throw new Error("No unspent coins available.");
135+
throw new Error('No unspent coins available.');
146136
}
147137
}
148138
}
149139

150140
// Reserve the selected coins
151141
selectedCoins.forEach((coin) => {
152-
const coinId = getCoinId(coin).toString("hex");
153-
cache.set(coinId, { coinId, expiry: Date.now() + CACHE_DURATION });
142+
const coinId = getCoinId(coin).toString('hex');
143+
cache.set(coinId, { coinId, expiry: Date.now() + COIN_CACHE_DURATION });
154144
});
155145

156146
return selectedCoins;

src/config/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
interface DigConfig {
2+
DIG_FOLDER_PATH: string;
3+
}
4+
5+
const config: DigConfig = {
6+
DIG_FOLDER_PATH: '.dig',
7+
};
8+
9+
export default config;

src/infrastructure/ConfigurationServices/NconfService.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@ import nconf from 'nconf';
22
import fs from 'fs-extra';
33
import { Mutex } from 'async-mutex';
44
import path from 'path';
5-
import os from 'os';
65
import { IConfigurationService } from '../../application/interfaces/IConfigurationService';
6+
import config from '../../config';
77

8-
export const CONF_FOLDER_PATH = path.join(os.homedir(), '.dig');
98
const fileMutex = new Mutex();
109

1110
export class NconfService implements IConfigurationService {
1211
private configFilePath: string;
1312

1413
constructor(relativePath: string) {
15-
this.configFilePath = path.join(CONF_FOLDER_PATH, relativePath);
14+
this.configFilePath = path.join(config.DIG_FOLDER_PATH, relativePath);
1615
this.initializeConfig();
1716
}
1817

test/application/services/FileCacheService.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import fs from 'fs';
22
import path from 'path';
3-
import { FileCacheService, DIG_FOLDER_PATH } from '../../../src/application/services/FileCacheService';
3+
import config from '../../../src/config';
4+
import { FileCacheService } from '../../../src/application/services/FileCacheService';
45

56
describe('FileCacheService', () => {
6-
const testDir = path.join(DIG_FOLDER_PATH, 'jest-test-cache');
7+
const testDir = path.join(config.DIG_FOLDER_PATH, 'jest-test-cache');
78
const key = 'testKey';
89
const value = { foo: 'bar', num: 42 };
910

test/application/services/WalletService.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,20 @@ describe('WalletService Integration', () => {
9191

9292
it('should return true if peer.isCoinSpent resolves true', async () => {
9393
peer.isCoinSpent.mockResolvedValue(true);
94-
const result = await WalletService.isCoinSpendable(peer, coinId);
94+
const result = await WalletService.isCoinSpendable(peer, coinId, 0, '00'.repeat(32));
9595
expect(result).toBe(true);
9696
expect(peer.isCoinSpent).toHaveBeenCalledWith(coinId, expect.any(Number), expect.any(Buffer));
9797
});
9898

9999
it('should return false if peer.isCoinSpent resolves false', async () => {
100100
peer.isCoinSpent.mockResolvedValue(false);
101-
const result = await WalletService.isCoinSpendable(peer, coinId);
101+
const result = await WalletService.isCoinSpendable(peer, coinId, 0, '00'.repeat(32));
102102
expect(result).toBe(false);
103103
});
104104

105105
it('should return false if peer.isCoinSpent throws', async () => {
106106
peer.isCoinSpent.mockRejectedValue(new Error('fail'));
107-
const result = await WalletService.isCoinSpendable(peer, coinId);
107+
const result = await WalletService.isCoinSpendable(peer, coinId, 0, '00'.repeat(32));
108108
expect(result).toBe(false);
109109
});
110110
});

test/application/types/Wallet.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ describe('Wallet', () => {
9393

9494
it('should select and reserve coins, respecting omitCoins and cache', async () => {
9595
const omitCoins = [{ id: '01', amount: 100n }];
96-
const result = await wallet.selectUnspentCoins(mockPeer, 50n, 10n, omitCoins);
96+
const result = await wallet.selectUnspentCoins(mockPeer, 50n, 10n, omitCoins, 0, '00'.repeat(32));
9797
expect(mockPeer.getAllUnspentCoins).toHaveBeenCalledWith(mockOwnerPuzzleHash, expect.any(Number), expect.any(Buffer));
9898
expect(Array.isArray(result)).toBe(true);
9999
expect(result.length).toBe(1);
@@ -106,15 +106,15 @@ describe('Wallet', () => {
106106
it('should throw if no coins and no reserved', async () => {
107107
mockPeer.getAllUnspentCoins.mockResolvedValue({ coins: [] });
108108
mockCache.getCachedKeys.mockReturnValue([]);
109-
await expect(wallet.selectUnspentCoins(mockPeer, 50n, 10n)).rejects.toThrow('No unspent coins available.');
109+
await expect(wallet.selectUnspentCoins(mockPeer, 50n, 10n, [], 0, '00'.repeat(32))).rejects.toThrow('No unspent coins available.');
110110
});
111111

112112
it('should retry if reserved coins exist', async () => {
113113
// Simulate reserved coins present, but no unspent coins
114114
mockPeer.getAllUnspentCoins.mockResolvedValue({ coins: [] });
115115
mockCache.getCachedKeys.mockReturnValue(['deadbeef']);
116116
mockCache.get.mockReturnValue({ coinId: 'deadbeef', expiry: Date.now() + 10000 });
117-
const promise = wallet.selectUnspentCoins(mockPeer, 50n, 10n);
117+
const promise = wallet.selectUnspentCoins(mockPeer, 50n, 10n, [], 0, '00'.repeat(32));
118118
// Fast-fail the wait
119119
jest.spyOn(global, 'setTimeout').mockImplementation((fn: any) => { fn(); return 0 as any; });
120120
setTimeout(() => promise.catch(() => {}), 20); // avoid unhandled rejection

0 commit comments

Comments
 (0)