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.cpp250
1 files changed, 238 insertions, 12 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 77aba89..252911b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -109,7 +109,11 @@ string strPayoutFile; // participant: /payoutfile with one addres
109int nHashThreads = 0; // participant: /hashthreads override (0 = cores-1) 109int nHashThreads = 0; // participant: /hashthreads override (0 = cores-1)
110string strPoolName = "Bitflash Pool"; 110string strPoolName = "Bitflash Pool";
111string strPoolDashboardUrl; 111string strPoolDashboardUrl;
112string strPoolStatusFile;
113string strPoolRoundsFile;
112double dPoolFeePercent = 0.0; 114double dPoolFeePercent = 0.0;
115bool fStratumBridge = false;
116int nStratumBridgePort = 3333;
113 117
114static std::atomic<uint64> gParticipantSharesSent{0}; 118static std::atomic<uint64> gParticipantSharesSent{0};
115static std::atomic<uint64> gParticipantSharesAccepted{0}; 119static std::atomic<uint64> gParticipantSharesAccepted{0};
@@ -190,6 +194,9 @@ int ParticipantHashThreadCount()
190 return nWorkers - 1; 194 return nWorkers - 1;
191} 195}
192 196
197static void SecureClearBytes(vector<unsigned char>& vch);
198static void SecureClearKeyingMaterial(CKeyingMaterial& vch);
199
193bool AddKey(const CKey& key) 200bool AddKey(const CKey& key)
194{ 201{
195 if (IsWalletEncrypted()) 202 if (IsWalletEncrypted())
@@ -199,9 +206,13 @@ bool AddKey(const CKey& key)
199 vector<unsigned char> vchCryptedSecret; 206 vector<unsigned char> vchCryptedSecret;
200 if (IsWalletLocked()) 207 if (IsWalletLocked())
201 return error("AddKey() : wallet is locked\n"); 208 return error("AddKey() : wallet is locked\n");
202 if (!EncryptSecret(vWalletMasterKey, vector<unsigned char>(vchPrivKey.begin(), vchPrivKey.end()), 209 vector<unsigned char> vchPlainSecret(vchPrivKey.begin(), vchPrivKey.end());
203 WalletKeyIV(key.GetPubKey()), vchCryptedSecret)) 210 if (!EncryptSecret(vWalletMasterKey, vchPlainSecret, WalletKeyIV(key.GetPubKey()), vchCryptedSecret))
211 {
212 SecureClearBytes(vchPlainSecret);
204 return error("AddKey() : encrypting key failed\n"); 213 return error("AddKey() : encrypting key failed\n");
214 }
215 SecureClearBytes(vchPlainSecret);
205 if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret)) 216 if (!AddCryptedKey(key.GetPubKey(), vchCryptedSecret))
206 return false; 217 return false;
207 return CWalletDB().WriteCryptedKey(key.GetPubKey(), vchCryptedSecret); 218 return CWalletDB().WriteCryptedKey(key.GetPubKey(), vchCryptedSecret);
@@ -225,17 +236,31 @@ bool IsWalletLocked()
225 return fWalletEncrypted && fWalletLocked; 236 return fWalletEncrypted && fWalletLocked;
226} 237}
227 238
239static void SecureClearBytes(vector<unsigned char>& vch)
240{
241 if (!vch.empty())
242 OPENSSL_cleanse(&vch[0], vch.size());
243 vch.clear();
244}
245
246static void SecureClearKeyingMaterial(CKeyingMaterial& vch)
247{
248 if (!vch.empty())
249 OPENSSL_cleanse(&vch[0], vch.size());
250 vch.clear();
251}
252
228void LockWallet() 253void LockWallet()
229{ 254{
230 if (!fWalletEncrypted) 255 if (!fWalletEncrypted)
231 return; 256 return;
232 CRITICAL_BLOCK(cs_mapKeys) 257 CRITICAL_BLOCK(cs_mapKeys)
233 { 258 {
234 vWalletMasterKey.clear(); 259 SecureClearKeyingMaterial(vWalletMasterKey);
235 if (!vchCryptedHDMaster.empty()) 260 if (!vchCryptedHDMaster.empty())
236 vchHDMaster.clear(); 261 SecureClearBytes(vchHDMaster);
237 if (!vchCryptedHDChainCode.empty()) 262 if (!vchCryptedHDChainCode.empty())
238 vchHDChainCode.clear(); 263 SecureClearBytes(vchHDChainCode);
239 fWalletLocked = true; 264 fWalletLocked = true;
240 } 265 }
241} 266}
@@ -260,14 +285,14 @@ bool DeriveWalletPassphraseKey(const string& strPassphrase,
260 chKey, chIV); 285 chKey, chIV);
261 if (n != 32) 286 if (n != 32)
262 { 287 {
263 memset(chKey, 0, sizeof(chKey)); 288 OPENSSL_cleanse(chKey, sizeof(chKey));
264 memset(chIV, 0, sizeof(chIV)); 289 OPENSSL_cleanse(chIV, sizeof(chIV));
265 return false; 290 return false;
266 } 291 }
267 vchKeyRet.assign(chKey, chKey + sizeof(chKey)); 292 vchKeyRet.assign(chKey, chKey + sizeof(chKey));
268 vchIVRet.assign(chIV, chIV + sizeof(chIV)); 293 vchIVRet.assign(chIV, chIV + sizeof(chIV));
269 memset(chKey, 0, sizeof(chKey)); 294 OPENSSL_cleanse(chKey, sizeof(chKey));
270 memset(chIV, 0, sizeof(chIV)); 295 OPENSSL_cleanse(chIV, sizeof(chIV));
271 return true; 296 return true;
272} 297}
273 298
@@ -328,6 +353,8 @@ bool DecryptSecret(const CKeyingMaterial& vchKey,
328 vchPlaintextRet.swap(vchOut); 353 vchPlaintextRet.swap(vchOut);
329 fOk = true; 354 fOk = true;
330 } 355 }
356 if (!fOk)
357 SecureClearBytes(vchOut);
331 EVP_CIPHER_CTX_free(ctx); 358 EVP_CIPHER_CTX_free(ctx);
332 return fOk; 359 return fOk;
333} 360}
@@ -403,6 +430,7 @@ bool GetWalletPrivKey(const vector<unsigned char>& vchPubKey,
403 } 430 }
404 431
405 CPrivKey vchPrivKey(vchPlaintext.begin(), vchPlaintext.end()); 432 CPrivKey vchPrivKey(vchPlaintext.begin(), vchPlaintext.end());
433 SecureClearBytes(vchPlaintext);
406 CKey key; 434 CKey key;
407 if (!key.SetPrivKey(vchPrivKey) || key.GetPubKey() != vchPubKey) 435 if (!key.SetPrivKey(vchPrivKey) || key.GetPubKey() != vchPubKey)
408 { 436 {
@@ -437,11 +465,20 @@ bool UnlockWallet(const string& strPassphrase, string& strErrorRet)
437 vector<unsigned char> vchMasterPlain; 465 vector<unsigned char> vchMasterPlain;
438 if (!DecryptSecret(vchPassKey, kMasterKey.vchCryptedKey, 466 if (!DecryptSecret(vchPassKey, kMasterKey.vchCryptedKey,
439 vchPassIV, vchMasterPlain)) 467 vchPassIV, vchMasterPlain))
468 {
469 SecureClearBytes(vchPassIV);
440 continue; 470 continue;
471 }
441 if (vchMasterPlain.size() != 32) 472 if (vchMasterPlain.size() != 32)
473 {
474 SecureClearBytes(vchMasterPlain);
475 SecureClearBytes(vchPassIV);
442 continue; 476 continue;
477 }
443 478
444 CKeyingMaterial vchCandidate(vchMasterPlain.begin(), vchMasterPlain.end()); 479 CKeyingMaterial vchCandidate(vchMasterPlain.begin(), vchMasterPlain.end());
480 SecureClearBytes(vchMasterPlain);
481 SecureClearBytes(vchPassIV);
445 bool fValid = mapCryptedKeys.empty(); 482 bool fValid = mapCryptedKeys.empty();
446 for (map<vector<unsigned char>, vector<unsigned char> >::iterator mci = mapCryptedKeys.begin(); 483 for (map<vector<unsigned char>, vector<unsigned char> >::iterator mci = mapCryptedKeys.begin();
447 mci != mapCryptedKeys.end(); ++mci) 484 mci != mapCryptedKeys.end(); ++mci)
@@ -450,6 +487,7 @@ bool UnlockWallet(const string& strPassphrase, string& strErrorRet)
450 if (!DecryptSecret(vchCandidate, (*mci).second, WalletKeyIV((*mci).first), vchPlaintext)) 487 if (!DecryptSecret(vchCandidate, (*mci).second, WalletKeyIV((*mci).first), vchPlaintext))
451 break; 488 break;
452 CPrivKey vchPrivKey(vchPlaintext.begin(), vchPlaintext.end()); 489 CPrivKey vchPrivKey(vchPlaintext.begin(), vchPlaintext.end());
490 SecureClearBytes(vchPlaintext);
453 CKey key; 491 CKey key;
454 if (key.SetPrivKey(vchPrivKey) && key.GetPubKey() == (*mci).first) 492 if (key.SetPrivKey(vchPrivKey) && key.GetPubKey() == (*mci).first)
455 fValid = true; 493 fValid = true;
@@ -465,10 +503,12 @@ bool UnlockWallet(const string& strPassphrase, string& strErrorRet)
465 WalletSecretIV("hdmaster"), vchPlainHDMaster) || 503 WalletSecretIV("hdmaster"), vchPlainHDMaster) ||
466 vchPlainHDMaster.size() != 32) 504 vchPlainHDMaster.size() != 32)
467 { 505 {
506 SecureClearBytes(vchPlainHDMaster);
468 strErrorRet = "could not decrypt HD master key"; 507 strErrorRet = "could not decrypt HD master key";
469 return false; 508 return false;
470 } 509 }
471 vchHDMaster = vchPlainHDMaster; 510 vchHDMaster = vchPlainHDMaster;
511 SecureClearBytes(vchPlainHDMaster);
472 } 512 }
473 if (!vchCryptedHDChainCode.empty()) 513 if (!vchCryptedHDChainCode.empty())
474 { 514 {
@@ -477,10 +517,12 @@ bool UnlockWallet(const string& strPassphrase, string& strErrorRet)
477 WalletSecretIV("hdchaincode"), vchPlainHDChainCode) || 517 WalletSecretIV("hdchaincode"), vchPlainHDChainCode) ||
478 vchPlainHDChainCode.size() != 32) 518 vchPlainHDChainCode.size() != 32)
479 { 519 {
520 SecureClearBytes(vchPlainHDChainCode);
480 strErrorRet = "could not decrypt HD chain code"; 521 strErrorRet = "could not decrypt HD chain code";
481 return false; 522 return false;
482 } 523 }
483 vchHDChainCode = vchPlainHDChainCode; 524 vchHDChainCode = vchPlainHDChainCode;
525 SecureClearBytes(vchPlainHDChainCode);
484 } 526 }
485 fWalletLocked = false; 527 fWalletLocked = false;
486 return true; 528 return true;
@@ -625,7 +667,7 @@ unsigned int nHDNext = 0;
625int nHDKeySchema = HD_SCHEMA_NONE; 667int nHDKeySchema = HD_SCHEMA_NONE;
626unsigned int nHDReceiveNext = 0; 668unsigned int nHDReceiveNext = 0;
627unsigned int nHDChangeNext = 0; 669unsigned int nHDChangeNext = 0;
628unsigned int nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH_PROVISIONAL; 670unsigned int nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH;
629 671
630string HDKeySchemaName(int nSchema) 672string HDKeySchemaName(int nSchema)
631{ 673{
@@ -781,7 +823,7 @@ bool SetHDSeedFromMnemonic(const string& strMnemonic, string& strErrorRet)
781 823
782 if (!CWalletDB().WriteHDMaster(master.privateKey, master.chainCode) || 824 if (!CWalletDB().WriteHDMaster(master.privateKey, master.chainCode) ||
783 !CWalletDB().WriteHDSchema(HD_SCHEMA_BIP44) || 825 !CWalletDB().WriteHDSchema(HD_SCHEMA_BIP44) ||
784 !CWalletDB().WriteHDCoinType(HD_BIP44_COIN_TYPE_BITFLASH_PROVISIONAL) || 826 !CWalletDB().WriteHDCoinType(HD_BIP44_COIN_TYPE_BITFLASH) ||
785 !CWalletDB().WriteHDNext(0) || 827 !CWalletDB().WriteHDNext(0) ||
786 !CWalletDB().WriteHDReceiveNext(1) || 828 !CWalletDB().WriteHDReceiveNext(1) ||
787 !CWalletDB().WriteHDChangeNext(0)) 829 !CWalletDB().WriteHDChangeNext(0))
@@ -794,7 +836,7 @@ bool SetHDSeedFromMnemonic(const string& strMnemonic, string& strErrorRet)
794 nHDKeySchema = HD_SCHEMA_BIP44; 836 nHDKeySchema = HD_SCHEMA_BIP44;
795 nHDReceiveNext = 1; 837 nHDReceiveNext = 1;
796 nHDChangeNext = 0; 838 nHDChangeNext = 0;
797 nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH_PROVISIONAL; 839 nHDCoinType = HD_BIP44_COIN_TYPE_BITFLASH;
798 840
799 // Index 0 is spoken for before it is derived, so a failure below cannot 841 // Index 0 is spoken for before it is derived, so a failure below cannot
800 // leave the pool free to hand it out as an ordinary key. The cost of 842 // leave the pool free to hand it out as an ordinary key. The cost of
@@ -4128,6 +4170,190 @@ connected:
4128 return true; 4170 return true;
4129} 4171}
4130 4172
4173// ---------------------------------------------------------------------------
4174// Local Stratum bridge -- lets external miners speak plain Stratum to
4175// 127.0.0.1 while Bitflash opens the .btf tunnel to the selected pool.
4176// ---------------------------------------------------------------------------
4177
4178struct StratumBridgeClientCtx
4179{
4180 SOCKET miner;
4181 std::string pool;
4182};
4183
4184static bool BridgeSendAll(SOCKET s, const char* p, int n)
4185{
4186 int off = 0;
4187 while (off < n)
4188 {
4189 int r = send(s, p + off, n - off, 0);
4190 if (r <= 0)
4191 return false;
4192 off += r;
4193 }
4194 return true;
4195}
4196
4197static void BridgePump(SOCKET a, SOCKET b)
4198{
4199 char buf[8192];
4200 while (!fShutdown)
4201 {
4202 fd_set rd;
4203 FD_ZERO(&rd);
4204 FD_SET(a, &rd);
4205 FD_SET(b, &rd);
4206 SOCKET maxfd = a > b ? a : b;
4207 struct timeval tv = {1, 0};
4208 int r = select((int)maxfd + 1, &rd, NULL, NULL, &tv);
4209 if (r <= 0)
4210 continue;
4211
4212 if (FD_ISSET(a, &rd))
4213 {
4214 int n = recv(a, buf, sizeof(buf), 0);
4215 if (n <= 0 || !BridgeSendAll(b, buf, n))
4216 break;
4217 }
4218 if (FD_ISSET(b, &rd))
4219 {
4220 int n = recv(b, buf, sizeof(buf), 0);
4221 if (n <= 0 || !BridgeSendAll(a, buf, n))
4222 break;
4223 }
4224 }
4225}
4226
4227static void ThreadStratumBridgeClient(void* arg)
4228{
4229 StratumBridgeClientCtx* ctx = (StratumBridgeClientCtx*)arg;
4230 SOCKET miner = ctx->miner;
4231 std::string pool = ctx->pool;
4232 delete ctx;
4233
4234 unsigned char target_pubkey[32];
4235 if (!btf::ParseAddress(pool, target_pubkey))
4236 {
4237 LogPrint("worker", "[bridge] invalid pool .btf address: %s\n", pool.c_str());
4238 BtfCloseSocket(miner);
4239 return;
4240 }
4241
4242 std::string meetingHostPort;
4243 unsigned char service_enc_pub[32];
4244 if (!BtfResolve(pool, meetingHostPort, service_enc_pub))
4245 {
4246 LogPrint("worker", "[bridge] failed to resolve pool %s\n", pool.c_str());
4247 BtfCloseSocket(miner);
4248 return;
4249 }
4250
4251 size_t colon = meetingHostPort.rfind(':');
4252 if (colon == std::string::npos)
4253 {
4254 LogPrint("worker", "[bridge] bad pool endpoint '%s'\n", meetingHostPort.c_str());
4255 BtfCloseSocket(miner);
4256 return;
4257 }
4258 std::string host = meetingHostPort.substr(0, colon);
4259 int port = atoi(meetingHostPort.substr(colon + 1).c_str());
4260 if (port <= 0 || port > 65535)
4261 {
4262 LogPrint("worker", "[bridge] bad pool port in '%s'\n", meetingHostPort.c_str());
4263 BtfCloseSocket(miner);
4264 return;
4265 }
4266
4267 SOCKET poolSock = btf::BtfClientTunnel(host.c_str(), (unsigned short)port,
4268 target_pubkey, service_enc_pub);
4269 if (poolSock == INVALID_SOCKET)
4270 {
4271 LogPrint("worker", "[bridge] tunnel connect failed for pool %s via %s\n",
4272 pool.c_str(), meetingHostPort.c_str());
4273 BtfCloseSocket(miner);
4274 return;
4275 }
4276
4277 LogPrint("worker", "[bridge] miner connected to pool %s via %s\n",
4278 pool.c_str(), meetingHostPort.c_str());
4279 BridgePump(miner, poolSock);
4280 BtfCloseSocket(poolSock);
4281 BtfCloseSocket(miner);
4282 LogPrint("worker", "[bridge] miner disconnected from pool %s\n", pool.c_str());
4283}
4284
4285void ThreadStratumBridge(void*)
4286{
4287 if (strParticipantPool.empty())
4288 {
4289 printf("Stratum bridge: no pool selected. Use /stratumbridge=POOL_BTF_ADDRESS\n");
4290 return;
4291 }
4292
4293 SOCKET listener = BtfSocketTag(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP),
4294 SOCK_STRATUM_BRIDGE);
4295 if (listener == INVALID_SOCKET)
4296 {
4297 printf("Stratum bridge: could not create listen socket\n");
4298 return;
4299 }
4300
4301 int yes = 1;
4302 setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
4303
4304 sockaddr_in addr;
4305 memset(&addr, 0, sizeof(addr));
4306 addr.sin_family = AF_INET;
4307 addr.sin_addr.s_addr = htonl(0x7f000001);
4308 addr.sin_port = htons((unsigned short)nStratumBridgePort);
4309
4310 if (bind(listener, (sockaddr*)&addr, sizeof(addr)) != 0 ||
4311 listen(listener, 16) != 0)
4312 {
4313 printf("Stratum bridge: could not listen on 127.0.0.1:%d\n",
4314 nStratumBridgePort);
4315 BtfCloseSocket(listener);
4316 return;
4317 }
4318
4319 printf("Stratum bridge: listening on 127.0.0.1:%d for pool %s\n",
4320 nStratumBridgePort, strParticipantPool.c_str());
4321
4322 while (!fShutdown)
4323 {
4324 fd_set rd;
4325 FD_ZERO(&rd);
4326 FD_SET(listener, &rd);
4327 struct timeval tv = {1, 0};
4328 if (select((int)listener + 1, &rd, NULL, NULL, &tv) <= 0)
4329 continue;
4330
4331 sockaddr_in cli;
4332#ifdef _WIN32
4333 int len = sizeof(cli);
4334#else
4335 socklen_t len = sizeof(cli);
4336#endif
4337 SOCKET miner = BtfSocketTag(accept(listener, (sockaddr*)&cli, &len),
4338 SOCK_STRATUM_BRIDGE);
4339 if (miner == INVALID_SOCKET)
4340 continue;
4341
4342 StratumBridgeClientCtx* ctx = new StratumBridgeClientCtx();
4343 ctx->miner = miner;
4344 ctx->pool = strParticipantPool;
4345 if (_beginthread(ThreadStratumBridgeClient, 0, ctx) == (uintptr_t)-1)
4346 {
4347 delete ctx;
4348 BtfCloseSocket(miner);
4349 LogPrint("worker", "[bridge] failed to spawn client thread\n");
4350 }
4351 }
4352
4353 BtfCloseSocket(listener);
4354 printf("Stratum bridge: stopped\n");
4355}
4356
4131bool BitcoinMiner(int nThreadId) 4357bool BitcoinMiner(int nThreadId)
4132{ 4358{
4133 // Relay mode: never mines, just relays/syncs. (Shouldn't normally get here 4359 // Relay mode: never mines, just relays/syncs. (Shouldn't normally get here