upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp112
1 files changed, 111 insertions, 1 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 82a98d2..e5754e6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -14,6 +14,7 @@
14#include <atomic> 14#include <atomic>
15#include <mutex> 15#include <mutex>
16#include <thread> 16#include <thread>
17#include "bip32.h"
17#include "btfaddr.h" 18#include "btfaddr.h"
18#include "btftunnel.h" 19#include "btftunnel.h"
19#ifndef _WIN32 20#ifndef _WIN32
@@ -178,6 +179,66 @@ vector<unsigned char> GenerateNewKey()
178CCriticalSection cs_keyPool; 179CCriticalSection cs_keyPool;
179map<int64, vector<unsigned char> > mapKeyPool; 180map<int64, vector<unsigned char> > mapKeyPool;
180 181
182vector<unsigned char> vchHDMaster;
183vector<unsigned char> vchHDChainCode;
184unsigned int nHDNext = 0;
185
186bool DeriveHDKey(unsigned int nIndex, CKey& keyRet, string& strErrorRet)
187{
188 if (!HaveHDSeed())
189 {
190 strErrorRet = "no seed";
191 return false;
192 }
193
194 bitflash::BIP32PrivateNode parent;
195 parent.privateKey = vchHDMaster;
196 parent.chainCode = vchHDChainCode;
197
198 bitflash::BIP32PrivateNode child;
199 if (!bitflash::BIP32DeriveHardenedChild(parent, nIndex, child, strErrorRet))
200 return false;
201
202 if (!keyRet.SetSecret(child.privateKey))
203 {
204 strErrorRet = "derived scalar is not a usable key";
205 return false;
206 }
207 return true;
208}
209
210bool SetHDSeedFromMnemonic(const string& strMnemonic, string& strErrorRet)
211{
212 string strNormalized;
213 if (!bitflash::BIP39ValidateMnemonic(strMnemonic, strNormalized, strErrorRet))
214 return false;
215
216 vector<unsigned char> vchSeed;
217 if (!bitflash::BIP39MnemonicToSeed(strNormalized, "", vchSeed, strErrorRet))
218 return false;
219
220 bitflash::BIP32PrivateNode master;
221 if (!bitflash::BIP32MasterFromSeed(vchSeed, master, strErrorRet))
222 return false;
223
224 CRITICAL_BLOCK(cs_keyPool)
225 {
226 // Written before the globals change, so a failed write leaves the
227 // wallet on the seed it already had rather than on one that exists
228 // only in memory.
229 if (!CWalletDB().WriteHDMaster(master.privateKey, master.chainCode) ||
230 !CWalletDB().WriteHDNext(0))
231 {
232 strErrorRet = "could not write the seed to wallet.dat";
233 return false;
234 }
235 vchHDMaster = master.privateKey;
236 vchHDChainCode = master.chainCode;
237 nHDNext = 0;
238 }
239 return true;
240}
241
181void TopUpKeyPool() 242void TopUpKeyPool()
182{ 243{
183 CRITICAL_BLOCK(cs_keyPool) 244 CRITICAL_BLOCK(cs_keyPool)
@@ -191,7 +252,30 @@ void TopUpKeyPool()
191 nIndex = (--mapKeyPool.end())->first + 1; 252 nIndex = (--mapKeyPool.end())->first + 1;
192 253
193 CKey key; 254 CKey key;
194 key.MakeNewKey(); 255 if (HaveHDSeed())
256 {
257 // Derived, so a recovery phrase can reproduce this exact key.
258 // A derivation that fails is not a reason to stop filling the
259 // pool -- fall back to a random key, which is what a wallet
260 // without a seed uses anyway. It will not come back from the
261 // phrase, and that is better than a node that cannot mine.
262 string strError;
263 if (DeriveHDKey(nHDNext, key, strError))
264 {
265 nHDNext++;
266 CWalletDB().WriteHDNext(nHDNext);
267 }
268 else
269 {
270 printf("TopUpKeyPool() : derivation at index %u failed (%s), "
271 "falling back to a random key\n", nHDNext, strError.c_str());
272 key.MakeNewKey();
273 }
274 }
275 else
276 {
277 key.MakeNewKey();
278 }
195 // AddKey writes the private key. Order matters: the key is in 279 // AddKey writes the private key. Order matters: the key is in
196 // wallet.dat before anything can point at it, so a crash between 280 // wallet.dat before anything can point at it, so a crash between
197 // the two writes costs an unused key, never a usable one. 281 // the two writes costs an unused key, never a usable one.
@@ -310,6 +394,32 @@ bool AddToWalletIfMine(const CTransaction& tx, const CBlock* pblock)
310 return true; 394 return true;
311} 395}
312 396
397bool CanScanWalletTransactions(string& strErrorRet)
398{
399 strErrorRet.clear();
400
401 if (pindexGenesisBlock == NULL || pindexBest == NULL || hashBestChain == 0 || nBestHeight < 0)
402 {
403 strErrorRet = "The block index is not loaded, so the wallet scan cannot "
404 "prove whether imported or restored keys own coins.";
405 return false;
406 }
407
408 if (nBestHeight == 0)
409 {
410 strErrorRet = "The local chain is only at height 0. A wallet scan would "
411 "inspect only the genesis block and could incorrectly "
412 "report zero transactions. Start the node and let it sync "
413 "before scanning. If this happened after copying a data "
414 "directory, keep wallet.dat safe and rebuild or re-download "
415 "the block data instead of trusting the copied database/ "
416 "environment.";
417 return false;
418 }
419
420 return true;
421}
422
313int ScanForWalletTransactions(CBlockIndex* pindexStart) 423int ScanForWalletTransactions(CBlockIndex* pindexStart)
314{ 424{
315 // Walk the chain looking for transactions that belong to keys this wallet 425 // Walk the chain looking for transactions that belong to keys this wallet