@pioneer-platform/pioneer-cache 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
package/dist/core/base-cache.js
CHANGED
|
@@ -151,9 +151,10 @@ class BaseCache {
|
|
|
151
151
|
const t0 = Date.now();
|
|
152
152
|
try {
|
|
153
153
|
// Redis timeout for cache reads
|
|
154
|
-
//
|
|
155
|
-
//
|
|
156
|
-
|
|
154
|
+
// PERFORMANCE FIX: Reduced from 10000ms to 100ms
|
|
155
|
+
// Local Redis should respond in <10ms. 100ms timeout prevents cascading failures
|
|
156
|
+
// when Redis is overloaded while still catching actual connection issues.
|
|
157
|
+
const timeoutMs = 100;
|
|
157
158
|
const cached = await Promise.race([
|
|
158
159
|
this.redis.get(key),
|
|
159
160
|
new Promise((resolve) => setTimeout(() => {
|
|
@@ -21,7 +21,12 @@ export declare class BalanceCache extends BaseCache<BalanceData> {
|
|
|
21
21
|
constructor(redis: any, balanceModule: any, config?: Partial<CacheConfig>);
|
|
22
22
|
/**
|
|
23
23
|
* Build Redis key for balance data
|
|
24
|
-
* Format: balance_v2:caip:
|
|
24
|
+
* Format: balance_v2:caip:hashedPubkey
|
|
25
|
+
*
|
|
26
|
+
* PRIVACY: Uses SHA-256 hash of pubkey/xpub instead of plaintext
|
|
27
|
+
* - One-way: cannot recover pubkey from hash
|
|
28
|
+
* - Deterministic: same pubkey always produces same key
|
|
29
|
+
* - Fast: ~0.02ms per hash
|
|
25
30
|
*/
|
|
26
31
|
protected buildKey(params: Record<string, any>): string;
|
|
27
32
|
/**
|
|
@@ -5,10 +5,42 @@
|
|
|
5
5
|
Extends BaseCache with balance-specific logic.
|
|
6
6
|
All common logic is inherited from BaseCache.
|
|
7
7
|
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
8
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
12
|
exports.BalanceCache = void 0;
|
|
10
13
|
const base_cache_1 = require("../core/base-cache");
|
|
14
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
11
15
|
const log = require('@pioneer-platform/loggerdog')();
|
|
16
|
+
/**
|
|
17
|
+
* Hash pubkey/xpub for privacy-protecting cache keys
|
|
18
|
+
* Uses SHA-256 for fast, deterministic, one-way hashing
|
|
19
|
+
*/
|
|
20
|
+
function hashPubkey(pubkey, salt = '') {
|
|
21
|
+
// Detect if this is an xpub (don't lowercase) or regular address (lowercase)
|
|
22
|
+
const isXpub = pubkey.match(/^[xyz]pub[1-9A-HJ-NP-Za-km-z]{100,}/);
|
|
23
|
+
const normalized = isXpub ? pubkey.trim() : pubkey.trim().toLowerCase();
|
|
24
|
+
const hash = crypto_1.default.createHash('sha256');
|
|
25
|
+
hash.update(normalized);
|
|
26
|
+
if (salt)
|
|
27
|
+
hash.update(salt);
|
|
28
|
+
// Return first 128 bits (32 hex chars) for shorter Redis keys
|
|
29
|
+
return hash.digest('hex').substring(0, 32);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Sanitize pubkey for safe logging
|
|
33
|
+
*/
|
|
34
|
+
function sanitizePubkey(pubkey) {
|
|
35
|
+
if (!pubkey || pubkey.length < 12)
|
|
36
|
+
return '[invalid]';
|
|
37
|
+
// Check if xpub (show first 8, last 8)
|
|
38
|
+
if (pubkey.match(/^[xyz]pub/)) {
|
|
39
|
+
return `${pubkey.substring(0, 8)}...${pubkey.substring(pubkey.length - 8)}`;
|
|
40
|
+
}
|
|
41
|
+
// Regular address (show first 6, last 4)
|
|
42
|
+
return `${pubkey.substring(0, 6)}...${pubkey.substring(pubkey.length - 4)}`;
|
|
43
|
+
}
|
|
12
44
|
/**
|
|
13
45
|
* BalanceCache - Caches blockchain balance data
|
|
14
46
|
*/
|
|
@@ -42,7 +74,12 @@ class BalanceCache extends base_cache_1.BaseCache {
|
|
|
42
74
|
}
|
|
43
75
|
/**
|
|
44
76
|
* Build Redis key for balance data
|
|
45
|
-
* Format: balance_v2:caip:
|
|
77
|
+
* Format: balance_v2:caip:hashedPubkey
|
|
78
|
+
*
|
|
79
|
+
* PRIVACY: Uses SHA-256 hash of pubkey/xpub instead of plaintext
|
|
80
|
+
* - One-way: cannot recover pubkey from hash
|
|
81
|
+
* - Deterministic: same pubkey always produces same key
|
|
82
|
+
* - Fast: ~0.02ms per hash
|
|
46
83
|
*/
|
|
47
84
|
buildKey(params) {
|
|
48
85
|
const { caip, pubkey } = params;
|
|
@@ -50,9 +87,9 @@ class BalanceCache extends base_cache_1.BaseCache {
|
|
|
50
87
|
throw new Error('BalanceCache.buildKey: caip and pubkey required');
|
|
51
88
|
}
|
|
52
89
|
const normalizedCaip = caip.toLowerCase();
|
|
53
|
-
//
|
|
54
|
-
const
|
|
55
|
-
return `${this.config.keyPrefix}${normalizedCaip}:${
|
|
90
|
+
// Hash pubkey for privacy protection
|
|
91
|
+
const hashedPubkey = hashPubkey(pubkey, caip);
|
|
92
|
+
return `${this.config.keyPrefix}${normalizedCaip}:${hashedPubkey}`;
|
|
56
93
|
}
|
|
57
94
|
/**
|
|
58
95
|
* Fetch balance from blockchain via balance module
|
|
@@ -61,12 +98,14 @@ class BalanceCache extends base_cache_1.BaseCache {
|
|
|
61
98
|
const tag = this.TAG + 'fetchFromSource | ';
|
|
62
99
|
try {
|
|
63
100
|
const { caip, pubkey } = params;
|
|
64
|
-
//
|
|
101
|
+
// Log sanitized pubkey for debugging
|
|
102
|
+
log.debug(tag, `Fetching balance for ${caip}/${sanitizePubkey(pubkey)}`);
|
|
103
|
+
// Fetch balance using balance module (still uses real pubkey)
|
|
65
104
|
const asset = { caip };
|
|
66
105
|
const owner = { pubkey };
|
|
67
106
|
const balanceInfo = await this.balanceModule.getBalance(asset, owner);
|
|
68
107
|
if (!balanceInfo || !balanceInfo.balance) {
|
|
69
|
-
log.warn(tag, `No balance returned for ${caip}/${pubkey
|
|
108
|
+
log.warn(tag, `No balance returned for ${caip}/${sanitizePubkey(pubkey)}`);
|
|
70
109
|
return {
|
|
71
110
|
caip,
|
|
72
111
|
pubkey,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pioneer-platform/pioneer-cache",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Unified caching system for Pioneer platform with Redis backend",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"author": "Pioneer Platform",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@pioneer-platform/loggerdog": "^8.
|
|
24
|
-
"@pioneer-platform/redis-queue": "^8.
|
|
25
|
-
"@pioneer-platform/default-redis": "^8.
|
|
23
|
+
"@pioneer-platform/loggerdog": "^8.11.0",
|
|
24
|
+
"@pioneer-platform/redis-queue": "^8.11.1",
|
|
25
|
+
"@pioneer-platform/default-redis": "^8.11.7"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^20.0.0",
|
package/src/core/base-cache.ts
CHANGED
|
@@ -185,9 +185,10 @@ export abstract class BaseCache<T> {
|
|
|
185
185
|
|
|
186
186
|
try {
|
|
187
187
|
// Redis timeout for cache reads
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
|
|
188
|
+
// PERFORMANCE FIX: Reduced from 10000ms to 100ms
|
|
189
|
+
// Local Redis should respond in <10ms. 100ms timeout prevents cascading failures
|
|
190
|
+
// when Redis is overloaded while still catching actual connection issues.
|
|
191
|
+
const timeoutMs = 100;
|
|
191
192
|
const cached = await Promise.race([
|
|
192
193
|
this.redis.get(key),
|
|
193
194
|
new Promise<null>((resolve) => setTimeout(() => {
|
|
@@ -7,9 +7,42 @@
|
|
|
7
7
|
|
|
8
8
|
import { BaseCache } from '../core/base-cache';
|
|
9
9
|
import type { CacheConfig } from '../types';
|
|
10
|
+
import crypto from 'crypto';
|
|
10
11
|
|
|
11
12
|
const log = require('@pioneer-platform/loggerdog')();
|
|
12
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Hash pubkey/xpub for privacy-protecting cache keys
|
|
16
|
+
* Uses SHA-256 for fast, deterministic, one-way hashing
|
|
17
|
+
*/
|
|
18
|
+
function hashPubkey(pubkey: string, salt: string = ''): string {
|
|
19
|
+
// Detect if this is an xpub (don't lowercase) or regular address (lowercase)
|
|
20
|
+
const isXpub = pubkey.match(/^[xyz]pub[1-9A-HJ-NP-Za-km-z]{100,}/);
|
|
21
|
+
const normalized = isXpub ? pubkey.trim() : pubkey.trim().toLowerCase();
|
|
22
|
+
|
|
23
|
+
const hash = crypto.createHash('sha256');
|
|
24
|
+
hash.update(normalized);
|
|
25
|
+
if (salt) hash.update(salt);
|
|
26
|
+
|
|
27
|
+
// Return first 128 bits (32 hex chars) for shorter Redis keys
|
|
28
|
+
return hash.digest('hex').substring(0, 32);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Sanitize pubkey for safe logging
|
|
33
|
+
*/
|
|
34
|
+
function sanitizePubkey(pubkey: string): string {
|
|
35
|
+
if (!pubkey || pubkey.length < 12) return '[invalid]';
|
|
36
|
+
|
|
37
|
+
// Check if xpub (show first 8, last 8)
|
|
38
|
+
if (pubkey.match(/^[xyz]pub/)) {
|
|
39
|
+
return `${pubkey.substring(0, 8)}...${pubkey.substring(pubkey.length - 8)}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Regular address (show first 6, last 4)
|
|
43
|
+
return `${pubkey.substring(0, 6)}...${pubkey.substring(pubkey.length - 4)}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
13
46
|
/**
|
|
14
47
|
* Balance data structure
|
|
15
48
|
*/
|
|
@@ -61,7 +94,12 @@ export class BalanceCache extends BaseCache<BalanceData> {
|
|
|
61
94
|
|
|
62
95
|
/**
|
|
63
96
|
* Build Redis key for balance data
|
|
64
|
-
* Format: balance_v2:caip:
|
|
97
|
+
* Format: balance_v2:caip:hashedPubkey
|
|
98
|
+
*
|
|
99
|
+
* PRIVACY: Uses SHA-256 hash of pubkey/xpub instead of plaintext
|
|
100
|
+
* - One-way: cannot recover pubkey from hash
|
|
101
|
+
* - Deterministic: same pubkey always produces same key
|
|
102
|
+
* - Fast: ~0.02ms per hash
|
|
65
103
|
*/
|
|
66
104
|
protected buildKey(params: Record<string, any>): string {
|
|
67
105
|
const { caip, pubkey } = params;
|
|
@@ -70,10 +108,11 @@ export class BalanceCache extends BaseCache<BalanceData> {
|
|
|
70
108
|
}
|
|
71
109
|
|
|
72
110
|
const normalizedCaip = caip.toLowerCase();
|
|
73
|
-
// Don't lowercase pubkeys - xpub/ypub/zpub are case-sensitive base58
|
|
74
|
-
const normalizedPubkey = pubkey;
|
|
75
111
|
|
|
76
|
-
|
|
112
|
+
// Hash pubkey for privacy protection
|
|
113
|
+
const hashedPubkey = hashPubkey(pubkey, caip);
|
|
114
|
+
|
|
115
|
+
return `${this.config.keyPrefix}${normalizedCaip}:${hashedPubkey}`;
|
|
77
116
|
}
|
|
78
117
|
|
|
79
118
|
/**
|
|
@@ -85,13 +124,16 @@ export class BalanceCache extends BaseCache<BalanceData> {
|
|
|
85
124
|
try {
|
|
86
125
|
const { caip, pubkey } = params;
|
|
87
126
|
|
|
88
|
-
//
|
|
127
|
+
// Log sanitized pubkey for debugging
|
|
128
|
+
log.debug(tag, `Fetching balance for ${caip}/${sanitizePubkey(pubkey)}`);
|
|
129
|
+
|
|
130
|
+
// Fetch balance using balance module (still uses real pubkey)
|
|
89
131
|
const asset = { caip };
|
|
90
132
|
const owner = { pubkey };
|
|
91
133
|
const balanceInfo = await this.balanceModule.getBalance(asset, owner);
|
|
92
134
|
|
|
93
135
|
if (!balanceInfo || !balanceInfo.balance) {
|
|
94
|
-
log.warn(tag, `No balance returned for ${caip}/${pubkey
|
|
136
|
+
log.warn(tag, `No balance returned for ${caip}/${sanitizePubkey(pubkey)}`);
|
|
95
137
|
return {
|
|
96
138
|
caip,
|
|
97
139
|
pubkey,
|