Skip to content

Commit 5ec0eac

Browse files
implement fallback from built-in scrypt to scryptsy/scrypt packages
This commit introduces an additional fallback behavior and console warning in the case that Node's built-in scrypt experiences memory exhaustion, as was discovered in the 1.x test suite with the static tests (see web3#2938). A large `n` parameter is the culprit, but that's not the case when using the 3rd party (deprecated) scrypt package. The `scryptsy` package can handle a large `n`, but performance does suffer considerably.
1 parent 02a251d commit 5ec0eac

1 file changed

Lines changed: 47 additions & 9 deletions

File tree

  • packages/web3-eth-accounts/src/crypto

packages/web3-eth-accounts/src/crypto/Scrypt.js

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,64 @@ let scrypt;
55
const isNode = Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]';
66
if (isNode) {
77
const NODE_MIN_VER_WITH_BUILTIN_SCRYPT = '10.5.0';
8+
const NODE_MIN_VER_INCOMPAT_SCRYPT_PKG = '12.0.0';
89
const semver = require('semver');
910
const useNodeBuiltin = isNode && semver.Range('>=' + NODE_MIN_VER_WITH_BUILTIN_SCRYPT).test(process.version);
1011

12+
const tryScryptPackage = (function() {
13+
let scryptPackage;
14+
return function() {
15+
if (scryptPackage !== undefined) {
16+
return scryptPackage;
17+
}
18+
try {
19+
scryptPackage = require('scrypt');
20+
} catch (error) {
21+
if (/was compiled against a different/.test(error.message)) {
22+
throw error;
23+
}
24+
scryptPackage = null;
25+
}
26+
return scryptPackage;
27+
};
28+
})();
29+
30+
const canImprove = function(nodeVer) {
31+
return `can improve web3's peformance when running Node.js versions older than ${nodeVer} by installing the (deprecated) scrypt package in your project`;
32+
};
33+
1134
if (useNodeBuiltin) {
1235
const crypto = require('crypto');
36+
let fallbackCount = 0;
1337
scrypt = function(key, salt, N, r, p, dkLength) {
14-
return crypto.scryptSync(key, salt, dkLength, {N, r, p});
38+
try {
39+
return crypto.scryptSync(key, salt, dkLength, {N, r, p});
40+
} catch (error) {
41+
if (/scrypt:memory limit exceeded/.test(error.message)) {
42+
const scryptPackage = tryScryptPackage();
43+
if (scryptPackage) {
44+
return scryptPackage.hashSync(key, {N: N, r: r, p: p}, dkLength, salt);
45+
}
46+
fallbackCount += 1;
47+
console.warn(
48+
'\u001B[33m%s\u001B[0m',
49+
`Memory limit exceeded for Node's built-in crypto.scrypt, falling back to scryptsy (times: ${fallbackCount}), if this happens frequently you ${canImprove(
50+
NODE_MIN_VER_INCOMPAT_SCRYPT_PKG
51+
)}`
52+
);
53+
return scryptsy(key, salt, N, r, p, dkLength);
54+
}
55+
throw error;
56+
}
1557
};
1658
} else {
17-
let scryptPackage;
18-
try {
19-
scryptPackage = require('scrypt');
59+
const scryptPackage = tryScryptPackage();
60+
if (scryptPackage) {
2061
scrypt = function(key, salt, N, r, p, dkLength) {
2162
return scryptPackage.hashSync(key, {N, r, p}, dkLength, salt);
2263
};
23-
} catch (error) {
24-
console.warn(
25-
'\u001B[33m%s\u001B[0m',
26-
`You can improve web3's peformance when running Node.js versions older than ${NODE_MIN_VER_WITH_BUILTIN_SCRYPT} by installing the (deprecated) scrypt package in your project`
27-
);
64+
} else {
65+
console.warn('\u001B[33m%s\u001B[0m', `You ${canImprove(NODE_MIN_VER_WITH_BUILTIN_SCRYPT)}`);
2866
}
2967
}
3068
}

0 commit comments

Comments
 (0)