Add MinGapLimit to WalletFile. Resolves
MODIFY
WalletWasabi.Tests/KeyManagementTests.cs
WalletWasabi.Tests/KeyManagementTests.cs
@@ -35,7 +35,7 @@ namespace WalletWasabi.Tests
Assert.NotNull(manager3.EncryptedSecret);
Assert.NotNull(manager3.ExtPubKey);
- var sameManager = new KeyManager(manager.EncryptedSecret, manager.ChainCode, manager.MasterFingerprint, manager.ExtPubKey, true, new BlockchainState());
+ var sameManager = new KeyManager(manager.EncryptedSecret, manager.ChainCode, manager.MasterFingerprint, manager.ExtPubKey, true, null, new BlockchainState());
var sameManager2 = new KeyManager(manager.EncryptedSecret, manager.ChainCode, password);
Logger.TurnOff();
Assert.Throws<SecurityException>(() => new KeyManager(manager.EncryptedSecret, manager.ChainCode, "differentPassword"));

MODIFY
WalletWasabi/KeyManagement/KeyManager.cs
WalletWasabi/KeyManagement/KeyManager.cs
@@ -37,11 +37,14 @@ namespace WalletWasabi.KeyManagement
public bool? PasswordVerified { get; private set; }
[JsonProperty(Order = 6)]
+ public int? MinGapLimit { get; private set; }
+
+ [JsonProperty(Order = 7)]
private BlockchainState BlockchainState { get; }
private object BlockchainStateLock { get; }
- [JsonProperty(Order = 7)]
+ [JsonProperty(Order = 8)]
private List<HdPubKey> HdPubKeys { get; }
private object HdPubKeysLock { get; }
@@ -66,8 +69,10 @@ namespace WalletWasabi.KeyManagement
public bool IsHardwareWallet => EncryptedSecret is null && MasterFingerprint != null;
public HardwareWalletInfo HardwareWalletInfo { get; set; }
+ private const int AbsoluteMinGapLimit = 21;
+
[JsonConstructor]
- public KeyManager(BitcoinEncryptedSecretNoEC encryptedSecret, byte[] chainCode, HDFingerprint? masterFingerprint, ExtPubKey extPubKey, bool? passwordVerified, BlockchainState blockchainState, string filePath = null)
+ public KeyManager(BitcoinEncryptedSecretNoEC encryptedSecret, byte[] chainCode, HDFingerprint? masterFingerprint, ExtPubKey extPubKey, bool? passwordVerified, int? minGapLimit, BlockchainState blockchainState, string filePath = null)
{
HdPubKeys = new List<HdPubKey>();
HdPubKeyScriptBytes = new List<byte[]>();
@@ -83,6 +88,7 @@ namespace WalletWasabi.KeyManagement
ExtPubKey = Guard.NotNull(nameof(extPubKey), extPubKey);
PasswordVerified = passwordVerified;
+ SetMinGaplimit(minGapLimit);
BlockchainState = blockchainState ?? new BlockchainState();
HardwareWalletInfo = null;
@@ -92,7 +98,7 @@ namespace WalletWasabi.KeyManagement
ToFile();
}
- public KeyManager(BitcoinEncryptedSecretNoEC encryptedSecret, byte[] chainCode, string password, string filePath = null)
+ public KeyManager(BitcoinEncryptedSecretNoEC encryptedSecret, byte[] chainCode, string password, int minGapLimit = AbsoluteMinGapLimit, string filePath = null)
{
HdPubKeys = new List<HdPubKey>();
HdPubKeyScriptBytes = new List<byte[]>();
@@ -109,6 +115,8 @@ namespace WalletWasabi.KeyManagement
password = "";
}
+ SetMinGaplimit(minGapLimit);
+
EncryptedSecret = Guard.NotNull(nameof(encryptedSecret), encryptedSecret);
ChainCode = Guard.NotNull(nameof(chainCode), chainCode);
var extKey = new ExtKey(encryptedSecret.GetKey(password), chainCode);
@@ -134,17 +142,17 @@ namespace WalletWasabi.KeyManagement
HDFingerprint masterFingerprint = extKey.Neuter().PubKey.GetHDFingerPrint();
ExtPubKey extPubKey = extKey.Derive(AccountKeyPath).Neuter();
- return new KeyManager(encryptedSecret, extKey.ChainCode, masterFingerprint, extPubKey, false, new BlockchainState(), filePath);
+ return new KeyManager(encryptedSecret, extKey.ChainCode, masterFingerprint, extPubKey, false, AbsoluteMinGapLimit, new BlockchainState(), filePath);
}
public static KeyManager CreateNewWatchOnly(ExtPubKey extPubKey, string filePath = null)
{
- return new KeyManager(null, null, null, extPubKey, null, new BlockchainState(), filePath);
+ return new KeyManager(null, null, null, extPubKey, null, AbsoluteMinGapLimit, new BlockchainState(), filePath);
}
public static KeyManager CreateNewHardwareWalletWatchOnly(HDFingerprint masterFingerpring, ExtPubKey extPubKey, string filePath = null)
{
- return new KeyManager(null, null, masterFingerpring, extPubKey, null, new BlockchainState(), filePath);
+ return new KeyManager(null, null, masterFingerpring, extPubKey, null, AbsoluteMinGapLimit, new BlockchainState(), filePath);
}
public static KeyManager Recover(Mnemonic mnemonic, string password, string filePath = null)
@@ -160,7 +168,20 @@ namespace WalletWasabi.KeyManagement
HDFingerprint masterFingerpring = extKey.Neuter().PubKey.GetHDFingerPrint();
ExtPubKey extPubKey = extKey.Derive(AccountKeyPath).Neuter();
- return new KeyManager(encryptedSecret, extKey.ChainCode, masterFingerpring, extPubKey, true, new BlockchainState(), filePath);
+ return new KeyManager(encryptedSecret, extKey.ChainCode, masterFingerpring, extPubKey, true, AbsoluteMinGapLimit, new BlockchainState(), filePath);
+ }
+
+ public void SetMinGaplimit(int? minGapLimit)
+ {
+ if (minGapLimit.HasValue)
+ {
+ MinGapLimit = Math.Max(AbsoluteMinGapLimit, minGapLimit.Value);
+ }
+ else
+ {
+ MinGapLimit = AbsoluteMinGapLimit;
+ }
+ // AssertCleanKeysIndexed(); Don't do this. Wallet file is null yet.
}
public void SetFilePath(string filePath)
@@ -522,19 +543,20 @@ namespace WalletWasabi.KeyManagement
/// <summary>
/// Make sure there's always clean keys generated and indexed.
+ /// Call SetMinGapLimit() to set how many keys should be asserted.
/// </summary>
- public bool AssertCleanKeysIndexed(int howMany = 21, bool? isInternal = null)
+ public bool AssertCleanKeysIndexed(bool? isInternal = null)
{
var generated = false;
if (isInternal is null)
{
- while (GetKeys(KeyState.Clean, true).Count() < howMany)
+ while (GetKeys(KeyState.Clean, true).Count() < MinGapLimit)
{
GenerateNewKey("", KeyState.Clean, true, toFile: false);
generated = true;
}
- while (GetKeys(KeyState.Clean, false).Count() < howMany)
+ while (GetKeys(KeyState.Clean, false).Count() < MinGapLimit)
{
GenerateNewKey("", KeyState.Clean, false, toFile: false);
generated = true;
@@ -542,7 +564,7 @@ namespace WalletWasabi.KeyManagement
}
else
{
- while (GetKeys(KeyState.Clean, isInternal).Count() < howMany)
+ while (GetKeys(KeyState.Clean, isInternal).Count() < MinGapLimit)
{
GenerateNewKey("", KeyState.Clean, (bool)isInternal, toFile: false);
generated = true;

MODIFY
WalletWasabi/Services/WalletService.cs
WalletWasabi/Services/WalletService.cs
@@ -106,7 +106,7 @@ namespace WalletWasabi.Services
BlockFolderLock = new AsyncLock();
BlockDownloadLock = new AsyncLock();
- KeyManager.AssertCleanKeysIndexed(21);
+ KeyManager.AssertCleanKeysIndexed();
KeyManager.AssertLockedInternalKeysIndexed(14);
_running = 0;
@@ -371,7 +371,7 @@ namespace WalletWasabi.Services
label = Guard.Correct(label);
// Make sure there's always 21 clean keys generated and indexed.
- KeyManager.AssertCleanKeysIndexed(21, false);
+ KeyManager.AssertCleanKeysIndexed(isInternal: false);
IEnumerable<HdPubKey> keys = KeyManager.GetKeys(KeyState.Clean, isInternal: false);
if (dontTouch != null)
@@ -635,7 +635,7 @@ namespace WalletWasabi.Services
}
// Make sure there's always 21 clean keys generated and indexed.
- KeyManager.AssertCleanKeysIndexed(21, foundKey.IsInternal);
+ KeyManager.AssertCleanKeysIndexed(isInternal: foundKey.IsInternal);
if (foundKey.IsInternal)
{
@@ -1169,7 +1169,7 @@ namespace WalletWasabi.Services
if (customChange is null)
{
- KeyManager.AssertCleanKeysIndexed(21, true);
+ KeyManager.AssertCleanKeysIndexed(isInternal: true);
KeyManager.AssertLockedInternalKeysIndexed(14);
var changeHdPubKey = KeyManager.GetKeys(KeyState.Clean, true).RandomElement();

Add MinGapLimit to WalletFile. Resolves https://github.com/zkSNACKs/WalletWasabi/issues/1256