diff --git a/supernode/index.html b/supernode/index.html index 2f0ed0c..9404cb8 100644 --- a/supernode/index.html +++ b/supernode/index.html @@ -9634,9 +9634,9 @@ value: { btc_mainnet: "https://blockexplorer.com", btc_testnet: "https://testnet.blockexplorer.com", - flo_mainnet: "https://livenet.flocha.in", - flo_testnet: "http://ranchimall1.duckdns.org:8080" - //flo_testnet: "https://testnet.flocha.in" + flo_mainnet: "http://flosight.duckdns.org", + //flo_testnet: "http://testnet-flosight.duckdns.org" + flo_testnet: "https://testnet.flocha.in" }, writable: false, configurable: false, @@ -10069,7 +10069,8 @@ // remove this line later // btcTradeMargin is tolerable difference between Crypto trader should deposit and cryptos he actually deposited RMAssets = - `tradableAsset1=BTC,FLO,BTC_TEST,FLO_TEST#!#tradableAsset2=INR,USD,BTC,FLO,BTC_TEST,FLO_TEST, + `masterFLOPubKey=029EF7838D4D103E62262394B5417E8ABFD75539D19E61CA5FD0C2051B69B29910 + #!#tradableAsset1=BTC,FLO,BTC_TEST,FLO_TEST#!#tradableAsset2=INR,USD,BTC,FLO,BTC_TEST,FLO_TEST, #!#validTradingAmount=10000,50000,100000,#!#btcTradeMargin=5000 #!#supernodesPubKeys=0315C3A20FE7096CC2E0F81A80D5F1A687B8F9EFA65242A0B0881E1BA3EE7D7D53, 03F7493F11B8E44B9798CD434D20FBE7FA34B9779D144984889D11A17C56A18742,039B4AA00DBFC0A6631DE6DA83526611A0E6B857D3579DF840BBDEAE8B6898E3B6, @@ -10154,6 +10155,7 @@ localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY); deposit_withdraw_user_claim_obj.userPubKey = localbitcoinplusplus.wallets.my_local_flo_public_key; + deposit_withdraw_user_claim_obj.trader_flo_address = localbitcoinplusplus.wallets.my_; deposit_withdraw_user_claim_obj.hash = deposit_withdraw_user_claim_hash; deposit_withdraw_user_claim_obj.sign = deposit_withdraw_user_claim_sign; @@ -10246,17 +10248,25 @@ launchKBucket: function(flo_id) { return new Promise((resolve, reject)=>{ try { - const KBucketId = localbitcoinplusplus.kademlia.floIdToKbucketId('FLO_TEST', flo_id) + const KBucketId = localbitcoinplusplus.kademlia.floIdToKbucketId('FLO_TEST', flo_id); const kbOptions = { localNodeId: KBucketId } window.KBucket = new BuildKBucket(kbOptions); - window.supernodeKBucket = new BuildKBucket(kbOptions); + + const master_flo_pubKey = localbitcoinplusplus.master_configurations.masterFLOPubKey; + const master_flo_addr = bitjs.FLO_TEST.pubkey2address(master_flo_pubKey); + if(typeof master_flo_pubKey !== "string") return reject(false); + const SuKBucketId = localbitcoinplusplus.kademlia.floIdToKbucketId('FLO_TEST', master_flo_addr); + const SukbOptions = { localNodeId: SuKBucketId } + window.supernodeKBucket = new BuildKBucket(SukbOptions); + resolve(true); } catch (error) { reject(error); } - }) + }); }, launchSupernodesKBucket: function() { + localbitcoinplusplus.master_configurations.supernodesPubKeys.map(pubKey=>{ return new Promise((resolve, reject)=>{ try { @@ -10426,10 +10436,10 @@ } }); }, - determineClosestSupernode: function(flo_addr, KB=supernodeKBucket, n=1) { + determineClosestSupernode: function(flo_addr, n=1, KB=supernodeKBucket) { return new Promise((resolve, reject)=>{ let msg = ``; - if (typeof KB !== "object") { + if (typeof supernodeKBucket !== "object") { msg = `ERROR: Supernode KBucket not found.`; showMessage(msg); reject(msg); @@ -10441,7 +10451,7 @@ if (!isFloIdUint8) { flo_addr = localbitcoinplusplus.kademlia.floIdToKbucketId('FLO_TEST', flo_addr); } - const closestSupernode = KB.closest(flo_addr, n); + const closestSupernode = supernodeKBucket.closest(flo_addr, n); resolve(closestSupernode); return true; } catch (error) { @@ -10633,7 +10643,10 @@ const RM_RPC = new localbitcoinplusplus.rpc; let bar = RM_RPC .send_rpc - .call(this, rpc_subject, {data: data, receiver_flo_address: flo_id}); + .call(this, rpc_subject, {data: data, + receiver_flo_address: flo_id, + trader_flo_address: localbitcoinplusplus.wallets.my_local_flo_address + }); doSend(bar); }); }, @@ -10641,6 +10654,7 @@ transmitMessageToMiddleMan: function (dataToBeSentToReceiver, receiverFloAddress) { const RM_RPC = new localbitcoinplusplus.rpc; dataToBeSentToReceiver.sender_flo_address = localbitcoinplusplus.wallets.my_local_flo_address; + dataToBeSentToReceiver.trader_flo_address = localbitcoinplusplus.wallets.my_local_flo_address let bar = RM_RPC .send_rpc .call(this, "MessageForMiddleman", dataToBeSentToReceiver); @@ -11058,15 +11072,24 @@ const RM_RPC = new localbitcoinplusplus.rpc; let store_pvtkey_req = RM_RPC .send_rpc - .call(this, "store_shamirs_secret_pvtkey_shares", - shares); - doSend(store_pvtkey_req); + .call(this, "store_shamirs_secret_pvtkey_shares", shares); + localbitcoinplusplus.kademlia.determineClosestSupernode(flo_id) + .then(my_closest_su=>{ + store_pvtkey_req.globalParams.primarySupernode = my_closest_su[0].data.id; + return store_pvtkey_req; + }).then((store_pvtkey_req)=>doSend(store_pvtkey_req)) }); return Promise.resolve(true); - } }, + getSupernodePublicKeyFromFloId: function(flo_id='') { + let su_arr = localbitcoinplusplus.master_configurations.supernodesPubKeys + .map(s=>[s, bitjs.FLO_TEST.pubkey2address(s)]) + .filter(f=>f[1]==flo_id); + + return su_arr[0]; + }, } @@ -11092,7 +11115,7 @@ request.globalParams.receiverFloId = params[0].receiver_flo_address; } - return request.toString(); + return request.toString(); }, filter_legit_requests: function (flo_id=null, callback) { @@ -11203,7 +11226,7 @@ let server_response = RM_RPC .send_rpc .call(this, "supernode_message", { - "trader_flo_id": respective_trader_id, + "trader_flo_address": respective_trader_id, "receiver_flo_address": respective_trader_id, "server_msg": request.response }); @@ -11230,7 +11253,7 @@ let server_response = RM_RPC .send_rpc .call(this, "supernode_message", { - "trader_flo_id": respective_trader_id, + "trader_flo_address": respective_trader_id, "receiver_flo_address": respective_trader_id, "server_msg": server_msg }); @@ -11439,6 +11462,7 @@ data: receivedTradeInfo }; deposit_response_object.receiver_flo_address = params.trader_flo_address; + deposit_response_object.trader_flo_address = params.trader_flo_address; let deposit_request_response = RM_RPC @@ -11487,7 +11511,12 @@ "store_shamirs_secret_pvtkey_shares", shares ); - doSend(store_pvtkey_req); + + localbitcoinplusplus.kademlia.determineClosestSupernode(flo_id) + .then(my_closest_su=>{ + store_pvtkey_req.globalParams.primarySupernode = my_closest_su[0].data.id; + return store_pvtkey_req; + }).then(store_pvtkey_req=>doSend(store_pvtkey_req)) }); if (typeof localbitcoinplusplus @@ -11552,6 +11581,7 @@ msg: `Please send the ${params.product} to ${generate_btc_keys_for_requester.address}.`, data: receivedTradeInfo, receiver_flo_address: params.trader_flo_address, + trader_flo_address: params.trader_flo_address, }; let deposit_request_response = @@ -11637,8 +11667,7 @@ updateinDB( "deposit", receivedTradeInfo, - receivedTradeInfo - .trader_flo_address + receivedTradeInfo.trader_flo_address ); let withdrawer_bank_account = withdrawer.receivinAddress; @@ -11650,6 +11679,7 @@ data: receivedTradeInfo, withdrawer_data: withdrawer, receiver_flo_address: receivedTradeInfo.trader_flo_address, + trader_flo_address: receivedTradeInfo.trader_flo_address, }; let @@ -11678,6 +11708,7 @@ msg: `Plese send the money to following bank address: "System determined bank".`, data: receivedTradeInfo, receiver_flo_address: receivedTradeInfo.trader_flo_address, + trader_flo_address: receivedTradeInfo.trader_flo_address, }; let deposit_request_response = @@ -11919,19 +11950,9 @@ vbl .deposited_btc_address ).then( - function ( - res - ) { - let - retrieve_pvtkey_req_id = - res[ - 0 - ] - .id; - res - [ - 0 - ] + function (res) { + let retrieve_pvtkey_req_id = res[0].id; + res[0] .btc_private_key_shamirs_id .map( bpks => { @@ -11947,10 +11968,12 @@ withdraw_id: vbl.withdraw_id } ); - doSend - ( - retrieve_pvtkey_req - ); + localbitcoinplusplus.kademlia + .determineClosestSupernode(localbitcoinplusplus.wallets.my_local_flo_address) + .then(my_closest_su=>{ + retrieve_pvtkey_req.globalParams.primarySupernode = my_closest_su[0].data.id; + return retrieve_pvtkey_req; + }).then(retrieve_pvtkey_req=>doSend(retrieve_pvtkey_req)); } ); }); @@ -12070,6 +12093,8 @@ // return back the response to client withdraw_request_db_object.receiver_flo_address = params.trader_flo_address; + withdraw_request_db_object.trader_flo_address = + params.trader_flo_address; let withdrawal_request_response = RM_RPC.send_rpc @@ -12077,9 +12102,7 @@ "withdrawal_request_response", withdraw_request_db_object ); - doSend( - withdrawal_request_response - ); + doSend(withdrawal_request_response); return true; } catch (error) { console.log(error); @@ -12253,10 +12276,7 @@ "updateUserCryptoBalanceRequest", updateUserCryptoBalanceObject ); - doSend - ( - updateUserCryptoBalanceRequestObject - ); + doSend(updateUserCryptoBalanceRequestObject); } ) @@ -12403,6 +12423,1273 @@ return request.toString(); // return to client }, + async backup_receive_rpc_response(request) { + var request = JSON.parse(request); + var params = request.params[0]; + var method = request.method; + + if (typeof params == "object" && typeof method == "string") { + + const RM_WALLET = new localbitcoinplusplus.wallets; + const RM_TRADE = new localbitcoinplusplus.trade; + const RM_RPC = new localbitcoinplusplus.rpc; + + let respective_trader_id = ''; + if (typeof params.trader_flo_address == "string") respective_trader_id = params.trader_flo_address; + request.response = {}; + let err_msg; + + if (method=="sync_with_supernode") { + RM_RPC.filter_legit_backup_requests(params.trader_flo_address, function (is_valid_request) { + if (is_valid_request === true && params.job == + "SYNC_MY_LOCAL_DB_WITH_SUPERNODE_DB" && params.trader_flo_address.length > + 0) { + const tableArray = ["deposit", "withdraw_cash", "withdraw_btc", + "crypto_balances", "cash_balances", "userPublicData" + ]; + localbitcoinplusplus.actions.get_sharable_db_data(tableArray).then( + function (su_db_data) { + if (typeof su_db_data == "object") { + su_db_data.trader_flo_address = params.trader_flo_address; + su_db_data.receiver_flo_address = params.trader_flo_address; + let server_sync_response = RM_RPC + .send_rpc + .call(this, "server_sync_response", + su_db_data); + doSend(server_sync_response); + } + }); + } + }); + } + + RM_RPC.filter_legit_backup_requests(params.trader_flo_address, async function (is_valid_request) { + if (is_valid_request !== true) return false; + + try { + + if(typeof res_obj.params[0].trader_flo_address !="string") return; + const my_closest_su_list = localbitcoinplusplus.kademlia.determineClosestSupernode(params.trader_flo_address); + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + // CHECK HERE IF USER IS INDULGED IN ANY MORE TRADE. IF TRUE RETURN ERROR + await backup_server_db_instance.backup_readAllDB("deposit").then(function (res) { + if (typeof res == "object" && res.length > 0) { + let canUserTrade = res.map(function (user) { + return respective_trader_id == user.trader_flo_address; + }); + if (canUserTrade.includes(true)) { + request.response = + `Trader id ${respective_trader_id} is not clear for trade currently. + You must finish your previous pending orders to qualify again to trade.`; + + const RM_RPC = new localbitcoinplusplus.rpc; + let server_response = RM_RPC + .send_rpc + .call(this, "supernode_message", { + "trader_flo_address": respective_trader_id, + "receiver_flo_address": respective_trader_id, + "server_msg": request.response + }); + doSend(server_response); + showMessage(request.response); + throw new Error(request.response); + return false; + } + } + }); + + // Check if user id is in deposit or withdraw. If true prevent him from trading + await backup_server_db_instance.backup_readAllDB('withdraw_cash').then(function (res) { + if (typeof res == "object") { + let check_deposit_withdraw_id_array = res.filter(f => f.status === 2) + .map(m => { + if (m.trader_flo_address == respective_trader_id || m.deposit_withdraw_id_array == + respective_trader_id) { + let server_msg = + `Trader id ${respective_trader_id} is not clear for trade currently. + You must finish your previous pending deposit/withdraw action to qualify again to trade.`; + + const RM_RPC = new localbitcoinplusplus.rpc; + let server_response = RM_RPC + .send_rpc + .call(this, "supernode_message", { + "trader_flo_address": respective_trader_id, + "receiver_flo_address": respective_trader_id, + "server_msg": server_msg + }); + doSend(server_response); + showMessage(server_msg); + throw new Error( + "User has not finished previous pending actions." + ); + } + }); + } + }); + } catch (error) { + throw new Error(error); + } + }); + + switch (method) { + case "trade_buy": + + RM_RPC.filter_legit_backup_requests(params.trader_flo_address, async function (is_valid_request) { + if (is_valid_request !== true) return false; + await RM_TRADE.resolve_current_crypto_price_in_fiat(params.product, + params.currency); + let trade_margin = await RM_TRADE.getAssetTradeAndWithdrawLimit( + params.trader_flo_address, params.product, params.currency); + if (typeof trade_margin.remaining_crypto_credit == "number" && + typeof trade_margin.remaining_fiat_credit == "number") { + if (trade_margin.remaining_fiat_credit > 0 && trade_margin.remaining_fiat_credit >= + params.buy_price) { + request.response = RM_TRADE.trade_buy.call(this, + ...request.params, + function (supernode_signed_res) { + supernode_signed_res.receiver_flo_address = params.trader_flo_address; + if (typeof supernode_signed_res == "object") { + let buy_request_response = RM_RPC + .send_rpc + .call(this, + "trade_buy_request_response", + supernode_signed_res); + doSend(buy_request_response); + // Init trading + RM_TRADE.createTradePipes(params.currency); + return true; + } + }); + } else { + err_msg = `Trade Margin Check Failed: You can only trade upto ${params.currency} ${trade_margin.remaining_fiat_credit}.`; + showMessage(err_msg); + throw new Error(err_msg); + } + } else { + err_msg = "Invalid trade margin figures."; + showMessage(err_msg); + throw new Error(err_msg); + } + + }); + break; + case "trade_sell": + RM_RPC.filter_legit_backup_requests(params.trader_flo_address, async function (is_valid_request) { + if (is_valid_request !== true) return false; + await RM_TRADE.resolve_current_crypto_price_in_fiat(params.product, + params.currency); + let trade_margin = await RM_TRADE.getAssetTradeAndWithdrawLimit( + params.trader_flo_address, params.product, params.currency); + if (typeof trade_margin.remaining_crypto_credit == "number" && + typeof trade_margin.remaining_fiat_credit == "number") { + let eqCrypto = RM_TRADE.calculateCryptoEquivalentOfCash(params.buy_price); + if (trade_margin.remaining_crypto_credit > 0 && trade_margin.remaining_crypto_credit >= + eqCrypto) { + request.response = RM_TRADE.trade_sell.call( + this, ...request.params, + function (supernode_signed_res) { + if (typeof supernode_signed_res == "object") { + supernode_signed_res.receiver_flo_address = params.trader_flo_address; + let sell_request_response = RM_RPC + .send_rpc + .call(this, + "trade_sell_request_response", + supernode_signed_res); + doSend(sell_request_response); + // Init trading + RM_TRADE.createTradePipes(params.currency); + return true; + } + } + ); + } else { + err_msg = `WARNING: Trade Margin Check Failed: + You can only trade upto ${params.currency} ${trade_margin.remaining_fiat_credit}.`; + + showMessage(err_msg); + throw new Error(err_msg); + } + } else { + err_msg = "Invalid trade margin figures."; + showMessage(err_msg); + throw new Error(err_msg); + } + }); + break; + case "sync_with_supernode": + // already processed above + break; + case "deposit_asset_request": + RM_RPC.filter_legit_backup_requests(params.trader_flo_address, function (is_valid_request) { + + if (is_valid_request !== true) return false; + + // This code will only run for supernodes + if (typeof params.product !== "undefined" && + (localbitcoinplusplus.master_configurations.tradableAsset1.includes( + params.product) || + localbitcoinplusplus.master_configurations.tradableAsset2.includes( + params.product)) && + typeof params.depositing_amount !== "undefined" && + localbitcoinplusplus.master_configurations.tradableAsset2.includes( + params.currency) && + typeof localbitcoinplusplus.master_configurations.validTradingAmount !== + 'undefined' && + localbitcoinplusplus.master_configurations.validTradingAmount.includes( + parseFloat(params.depositing_amount)) && + typeof params.trader_flo_address == "string" && + params.trader_flo_address.length > 0 + ) { + RM_WALLET.getUserPublicKey(params.trader_flo_address, + async function (requester_public_key) { + if (requester_public_key == undefined || + requester_public_key == null) { + err_msg = 'Failed to get public key of the user.'; + showMessage(err_msg); + throw new Error(err_msg); + } + params.depositor_public_key = requester_public_key; + + await RM_TRADE.resolve_current_crypto_price_in_fiat( + params.product, params.currency); + + if (localbitcoinplusplus.master_configurations.tradableAsset1 + .includes(params.product)) { + + let generate_btc_keys_for_requester = RM_WALLET + .generateFloKeys(null, params.product); + + params.id = helper_functions.unique_id(); + params.status = 1; + params.btc_address = + generate_btc_keys_for_requester.address; + + params.bitcoinToBePaid = RM_TRADE.calculateCryptoEquivalentOfCash( + params.depositing_amount, params.currency, + params.product); + + let receivedTradeInfo = { ...params }; + + if (typeof localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY == + "undefined") { + err_msg = 'Failed to determine Super node signing key.'; + showMessage(err_msg); + throw new Error(err_msg); + } + + backup_server_db_instance.backup_readDB("localbitcoinUser", "00-01").then( + function (su_data) { + if (typeof su_data == "object" && + typeof su_data.myLocalFLOPublicKey == + "string" && + su_data.myLocalFLOPublicKey.length > + 0 && + localbitcoinplusplus.master_configurations + .supernodesPubKeys + .includes(su_data.myLocalFLOPublicKey) + ) { + + let receivedTradeInfoHash = + Crypto.SHA256(JSON.stringify(receivedTradeInfo)); + + receivedTradeInfo["depositDataHash"] = receivedTradeInfoHash; + receivedTradeInfo["order_validator_sign"] = + RM_WALLET.sign(receivedTradeInfoHash, + localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY + ); + receivedTradeInfo["order_validator_public_key"] = su_data.myLocalFLOPublicKey; + + try { + const this_btc_pvt_key = + generate_btc_keys_for_requester.privateKeyWIF; + const this_btc_tx_key = + Crypto.util.randomBytes(64); + const + this_btc_pvt_key_shamirs_secret = + RM_WALLET.createShamirsSecretShares(this_btc_pvt_key, 10, 5); + if (typeof this_btc_pvt_key_shamirs_secret == + "object" && + this_btc_pvt_key_shamirs_secret + .length > 0) { + backup_server_db_instance.backup_addDB("deposit", receivedTradeInfo); + + // Send the address to the requester + let + deposit_response_object = { + error: false, + method: "deposit_asset_request_response", + msg: `Please send ${params.product} ${params.bitcoinToBePaid} to the following addres: ${generate_btc_keys_for_requester.address}.`, + data: receivedTradeInfo + }; + deposit_response_object.receiver_flo_address = params.trader_flo_address; + deposit_response_object.trader_flo_address = params.trader_flo_address; + let + deposit_request_response = + RM_RPC + .send_rpc + .call(this, + "deposit_asset_request_response", + deposit_response_object + ); + doSend(deposit_request_response); + + let + this_btc_pvt_key_shamirs_secret_array = + this_btc_pvt_key_shamirs_secret + .map(chunks => { + let + chunk_ids = + Crypto.util + .bytesToHex( + Crypto + .util + .randomBytes( + 64 + )); + let + chunk_array = { + "id": chunk_ids, + "privateKeyChunks": Crypto + .AES + .encrypt( + chunks, + this_btc_tx_key + ) + }; + return chunk_array; + }); + + // Send chunks of private keys to other supernodes + this_btc_pvt_key_shamirs_secret_array + .map(shares => { + let + store_pvtkey_req = + RM_RPC + .send_rpc + .call( + this, + "store_shamirs_secret_pvtkey_shares", + shares + ); + + localbitcoinplusplus.kademlia.determineClosestSupernode(flo_id) + .then(my_closest_su=>{ + store_pvtkey_req.globalParams.primarySupernode = my_closest_su[0].data.id; + return store_pvtkey_req; + }).then(store_pvtkey_req=>doSend(store_pvtkey_req)) + }); + + if (typeof localbitcoinplusplus + .wallets.my_local_flo_address == + "string" && + typeof localbitcoinplusplus + .wallets.my_local_flo_public_key == + "string" && + typeof localbitcoinplusplus + .master_configurations + .supernodesPubKeys == + "object" && + localbitcoinplusplus + .master_configurations + .supernodesPubKeys.includes( + localbitcoinplusplus + .wallets.my_local_flo_public_key + )) { + try { + let + this_btc_pvt_key_shamirs_secret__id_array = + this_btc_pvt_key_shamirs_secret_array + .map(i => i.id); + let + btc_private_key_shamirs_id = + this_btc_pvt_key_shamirs_secret__id_array; + let + supernode_transaction_key = + this_btc_tx_key; + const + system_btc_reserves_private_keys_object = { + id: helper_functions + .unique_id(), + product: params + .product, + btc_address: params + .btc_address, + balance: null, + trader_flo_address: params + .trader_flo_address, + btc_private_key_shamirs_id: btc_private_key_shamirs_id, + supernode_transaction_key: supernode_transaction_key + } + backup_server_db_instance.backup_addDB( + "system_btc_reserves_private_keys", + system_btc_reserves_private_keys_object + ); + } catch (error) { + throw new Error( error); + } + } + return true; + } + } catch (error) { + throw new Error(error); + } + + // Send the address to the requester + let deposit_response_object = { + error: false, + method: "deposit_asset_request_response", + msg: `Please send the ${params.product} to ${generate_btc_keys_for_requester.address}.`, + data: receivedTradeInfo, + receiver_flo_address: params.trader_flo_address, + trader_flo_address: params.trader_flo_address, + }; + + let deposit_request_response = + RM_RPC.send_rpc + .call(this, + "deposit_asset_request_response", + deposit_response_object + ); + doSend(deposit_request_response); + return true; + } + }); + + return false; + + } else if (!localbitcoinplusplus.master_configurations + .tradableAsset1.includes(params.product)) { + params.id = helper_functions.unique_id(); + params.status = 1; + // IMPORTANT - If deposit is a fiat make sure product and currency are both same + params.currency = params.product; + let receivedTradeInfo = { ...params }; + + backup_server_db_instance.backup_readDB("localbitcoinUser", "00-01").then( + function (su_data) { + if (typeof su_data == "object" && + typeof su_data.myLocalFLOPublicKey == + "string" && + su_data.myLocalFLOPublicKey.length > + 0 && + localbitcoinplusplus.master_configurations + .supernodesPubKeys + .includes(su_data.myLocalFLOPublicKey) + ) { + let receivedTradeInfoHash = + Crypto.SHA256(JSON.stringify( + receivedTradeInfo)); + + receivedTradeInfo[ + "depositDataHash"] = + receivedTradeInfoHash; + receivedTradeInfo[ + "order_validator_sign"] = + RM_WALLET.sign( + receivedTradeInfoHash, + localbitcoinplusplus.wallets + .MY_SUPERNODE_PRIVATE_KEY + ); + receivedTradeInfo[ + "order_validator_public_key" + ] = su_data.myLocalFLOPublicKey; + + // YOU NEED TO DETERMINE A BANK ACCOUNT HERE IF NO ONE IS WITHDRAWING + try { + backup_server_db_instance.backup_addDB("deposit", + receivedTradeInfo); + backup_server_db_instance.backup_readDBbyIndex( + "withdraw_cash", + "status", 1).then( + function ( + withdrawers_list + ) { + if (typeof withdrawers_list == + "object") { + if ( + withdrawers_list.length > 0) { + withdrawers_list.filter( + wd => wd.currency == + params.currency).map( + function (withdrawer) { + if ( + withdrawer.withdraw_amount == + params.depositing_amount && + withdrawer.currency == + params.currency + ) { + withdrawer.status = 2; // A depositor has been asked to deposit money + withdrawer.depositor_found_at = + new Date(); + withdrawer.depositor_flo_id = receivedTradeInfo.trader_flo_address; + backup_server_db_instance.backup_updateinDB ("withdraw_cash", withdrawer, withdrawer.trader_flo_address); + + receivedTradeInfo.status = 2; // withdrawer found. Now deposit money to his account + backup_server_db_instance.backup_updateinDB( + "deposit", + receivedTradeInfo, + receivedTradeInfo.trader_flo_address + ); + + let withdrawer_bank_account = withdrawer.receivinAddress; + + let deposit_response_object = { + error: false, + method: "deposit_asset_request_response", + msg: `Plese send the money to following bank address: "${withdrawer_bank_account}"`, + data: receivedTradeInfo, + withdrawer_data: withdrawer, + receiver_flo_address: receivedTradeInfo.trader_flo_address, + trader_flo_address: receivedTradeInfo.trader_flo_address, + }; + + let + deposit_request_response = + RM_RPC.send_rpc.call( + this, + "deposit_asset_request_response", + deposit_response_object + ); + + doSend(deposit_request_response); + return true; + } else { + err_msg = "Deposit request failed: We could not find a withdrawer."; + showMessage(err_msg); + throw new Error(err_msg); + } + } + ); + } else { + //No one is withdrawing so provide your bank details + let + deposit_response_object = { + error: false, + method: "deposit_asset_request_response", + msg: `Plese send the money to following bank address: "System determined bank".`, + data: receivedTradeInfo, + receiver_flo_address: receivedTradeInfo.trader_flo_address, + trader_flo_address: receivedTradeInfo.trader_flo_address, + }; + let + deposit_request_response = + RM_RPC + .send_rpc + .call( + this, + "deposit_asset_request_response", + deposit_response_object + ); + + receivedTradeInfo.status = 2; // withdrawer found. Now deposit money to his account + updateinDB + ( + "deposit", + receivedTradeInfo, + receivedTradeInfo + .trader_flo_address + ); + + doSend(deposit_request_response); + return true; + } + } + }); + } catch (error) { + err_msg = "Deposit request failed: We could not find a withdrawer. Come again later."; + showMessage(err_msg); + throw new Error(err_msg); + } + + } + }); + } + }); + + } else { + err_msg = "deposit asset request error"; + showMessage(err_msg); + throw new Error(err_msg); + } + }); + break; + case "withdraw_request_method": + RM_RPC.filter_legit_backup_requests(params.trader_flo_address, async function (is_valid_request) { + + if (is_valid_request !== true) return false; + + if (typeof params.product !== "undefined" && + (localbitcoinplusplus.master_configurations.tradableAsset1.includes( + params.product) || + localbitcoinplusplus.master_configurations.tradableAsset2.includes( + params.currency)) && + typeof params.withdrawing_amount !== "undefined" && + typeof localbitcoinplusplus.master_configurations.validTradingAmount !== + 'undefined' && + localbitcoinplusplus.master_configurations.validTradingAmount.includes( + parseFloat(params.withdrawing_amount)) && + typeof params.trader_flo_address == "string" && params.trader_flo_address + .length > 0 && + typeof params.receivinAddress == "string" && params.receivinAddress + .length > + 0 && typeof params.currency == "string" + ) { + await RM_TRADE.resolve_current_crypto_price_in_fiat(params.product, + params.currency); + let trade_margin = await RM_TRADE.getAssetTradeAndWithdrawLimit( + params.trader_flo_address, params.product, params.currency + ); + + if (localbitcoinplusplus.master_configurations.tradableAsset1.includes( + params.product)) { + let eqCrypto = RM_TRADE.calculateCryptoEquivalentOfCash( + params.withdrawing_amount); + if (trade_margin.remaining_crypto_credit < 0 && + trade_margin.remaining_crypto_credit < eqCrypto) { + err_msg = `Insufficient crypto balance to withdraw. You can withdraw upto: ${params.product} ${trade_margin.remaining_crypto_credit}` + showMessage(err_msg); + throw new Error(err_msg); + } + } else { + if (trade_margin.remaining_fiat_credit < 0 && trade_margin.remaining_fiat_credit < + params.withdrawing_amount) { + err_msg = `Insufficient fiat balance to withdraw. You can withdraw upto: ${params.currency} ${trade_margin.remaining_fiat_credit}`; + showMessage(err_msg); + throw new Error(err_msg); + } + } + + params.id = helper_functions.unique_id(); + params.status = 1; + if (localbitcoinplusplus.master_configurations.tradableAsset1.includes( + params.product)) { + // Check how much cryptos the user can withdraw + let withdrawer_btc_id = + `${params.trader_flo_address}_${params.product}`; + backup_server_db_instance.backup_readDB("crypto_balances", withdrawer_btc_id).then(function ( + btc_balance_res) { + if (typeof btc_balance_res == "object" && + typeof btc_balance_res + .trader_flo_address == "string" && + btc_balance_res.crypto_balance > 0) { + let withdrawer_btc_balance = parseFloat( + btc_balance_res.crypto_balance); + let withdrawing_btc_amount_in_cash = + parseFloat(params.withdrawing_amount); + if (!localbitcoinplusplus.master_configurations + .tradableAsset2.includes(params.currency) + ) { + err_msg = "Invalid or unsupported currency."; + showMessage(err_msg); + throw new Error(err_msg); + } + let eqBTC = RM_TRADE.calculateCryptoEquivalentOfCash( + withdrawing_btc_amount_in_cash, + params.currency, params.product); + eqBTC = parseFloat(eqBTC).toFixed(8); + let withdrawer_new_btc_balance = + withdrawer_btc_balance - eqBTC; + if (withdrawer_new_btc_balance > 0 && + withdrawer_btc_balance > 0 && + withdrawing_btc_amount_in_cash > 0 && + eqBTC > 0 && eqBTC <= + withdrawer_btc_balance) { + + // Now details of Bitcoins can be sent to withdrawer + + /**************************************************************************** + ***********IMPORTANT: CHANGE RECEIVING ADDRESS TO BTC THAN FLO HERE********** + ***********AND DO SOMETHING ABOUT PRIVATE KEY BELOW************************** + ****************************************************************************/ + let sum_total_btc = 0; + let valid_utxo_list = []; + let receiverBTCAddress = params.receivinAddress + .trim(); + + backup_server_db_instance.backup_readAllDB("deposit").then(function ( + deposit_list) { + if (typeof deposit_list == + "object" && + deposit_list.length > 0 + ) { + deposit_list = + deposit_list.filter( + deposits => + deposits.status == + 2 && + localbitcoinplusplus + .master_configurations + .tradableAsset1 + .includes( + deposits.product + ) && + params.product == + deposits.product + ); + for (const dl in + deposit_list) { + if (deposit_list.hasOwnProperty( + dl)) { + const deposit_dl = + deposit_list[ + dl]; + sum_total_btc += + parseFloat( + deposit_dl + .bitcoinToBePaid + ); + + if (eqBTC <= + sum_total_btc + ) { + valid_utxo_list + .push( + deposit_dl + ); + break; + } else { + valid_utxo_list + .push( + deposit_dl + ); + } + } + } + let valid_btc_list = + valid_utxo_list.map( + deposit_arr => { + deposit_arr + .status = + 3 // Deposited Bitcoin is under process + backup_server_db_instance.backup_updateinDB( + "deposit", + deposit_arr, + deposit_arr + .trader_flo_address + ); + + // save the address and id in a table + let + withdraw_id = + helper_functions + .unique_id(); + const + withdraw_btc_order_object = { + id: withdraw_id, + trader_flo_address: params + .trader_flo_address, + utxo_addr: deposit_arr + .btc_address, + receiverBTCAddress: params + .receivinAddress, + receiverBTCEquivalentInCash: withdrawing_btc_amount_in_cash, + currency: params + .currency, + product: params + .product, + change_adress: deposit_arr + .btc_address, + timestamp: + new Date() + } + backup_server_db_instance.backup_addDB( + 'withdraw_btc', + withdraw_btc_order_object + ); + return { + withdraw_id: withdraw_id, + deposited_btc_address: deposit_arr + .btc_address + }; + }); + + // doSend btc_private_key_shamirs_id from system_btc_reserves_private_keys + valid_btc_list.map(vbl => { + readDBbyIndex + ( + 'system_btc_reserves_private_keys', + 'btc_address', + vbl + .deposited_btc_address + ).then( + function (res) { + let retrieve_pvtkey_req_id = res[0].id; + res[0] + .btc_private_key_shamirs_id + .map( + bpks => { + let + retrieve_pvtkey_req = + RM_RPC + .send_rpc + .call( + this, + "send_back_shamirs_secret_btc_pvtkey", { + retrieve_pvtkey_req_id: retrieve_pvtkey_req_id, + chunk_val: bpks, + withdraw_id: vbl.withdraw_id + } + ); + localbitcoinplusplus.kademlia + .determineClosestSupernode(localbitcoinplusplus.wallets.my_local_flo_address) + .then(my_closest_su=>{ + retrieve_pvtkey_req.globalParams.primarySupernode = my_closest_su[0].data.id; + return retrieve_pvtkey_req; + }).then(retrieve_pvtkey_req=>doSend(retrieve_pvtkey_req)); + } + ); + }); + }); + + } + }); + + } else { + err_msg = `Withdrawal request failed: You are trying to withdraw more Bitcoins than you have.`; + showMessage(err_msg); + throw new Error(err_msg); + + // Return error to the requester + return { + error: true, + method: "withdrawal_request_response", + data: "Withdrawal request failed: You are trying to withdraw more Bitcoins than you have." + }; + } + } else { + err_msg = + `Withdrawal request failed: You don't seem to have any Bitcoin balance in the system yet. + Please buy some Bitcoins to withdraw.`; + showMessage(err_msg); + + // Return error to the requester + return { + error: true, + method: "withdrawal_request_response", + data: `Withdrawal request failed: You don't seem to have any Bitcoin balance in the system yet. + Please buy some Bitcoins to withdraw.` + }; + } + }); + } else if (!localbitcoinplusplus.master_configurations.tradableAsset1 + .includes(params.product)) { + // Check if there's no already a withdraw cash order of this user + /*ONLY DELETE A WITHDRAW ORDER WHEN A DEPOSITOR HAS CONFIRMED DEPOSIT + AND RECEIVER HAS CONFIRMED WITHDRAW*/ + + // Check how much Cash user can withdraw + const trader_cash_id = + `${params.trader_flo_address}_${params.currency}`; + backup_server_db_instance.backup_readDB("cash_balances", trader_cash_id).then(function ( + cash_balances_res) { + if (typeof cash_balances_res == "object" && + typeof cash_balances_res + .trader_flo_address == "string" && + typeof cash_balances_res.cash_balance == + "number" && + cash_balances_res.cash_balance > 0) { + let withdrawer_cash_balance = parseFloat( + cash_balances_res.cash_balance); + let withdrawing_cash_amount = parseFloat( + params.withdrawing_amount); + let bank_details = params.receivinAddress.trim(); + + if (withdrawer_cash_balance > 0 && + withdrawing_cash_amount > 0 && + withdrawer_cash_balance >= + withdrawing_cash_amount) { + // Add it to cash withdrawal table + let withdraw_request_db_object = { + id: helper_functions.unique_id(), + trader_flo_address: params.trader_flo_address, + withdraw_amount: withdrawing_cash_amount, + currency: params.currency, + receivinAddress: bank_details, + status: 1, // withdraw request called + } + + backup_server_db_instance.backup_readDB("localbitcoinUser", "00-01").then( + function ( + su_data) { + if (typeof su_data == + "object" && + typeof su_data.myLocalFLOPublicKey == + "string" && + su_data.myLocalFLOPublicKey + .length > + 0 && + localbitcoinplusplus.master_configurations + .supernodesPubKeys.includes( + su_data.myLocalFLOPublicKey + )) { + + let + withdraw_request_db_object_hash = + Crypto.SHA256(JSON.stringify( + withdraw_request_db_object + )); + withdraw_request_db_object + ["withdrawDataHash"] = + withdraw_request_db_object_hash; + withdraw_request_db_object + [ + "order_validator_sign" + ] = + RM_WALLET + .sign( + withdraw_request_db_object_hash, + localbitcoinplusplus + .wallets.MY_SUPERNODE_PRIVATE_KEY + ); + withdraw_request_db_object + [ + "order_validator_public_key" + ] = su_data.myLocalFLOPublicKey; + + try { + // add the request to supernode db + backup_server_db_instance.backup_addDB( + "withdraw_cash", + withdraw_request_db_object + ); + // return back the response to client + withdraw_request_db_object.receiver_flo_address = + params.trader_flo_address; + withdraw_request_db_object.trader_flo_address = + params.trader_flo_address; + let + withdrawal_request_response = + RM_RPC.send_rpc + .call(this, + "withdrawal_request_response", + withdraw_request_db_object + ); + doSend(withdrawal_request_response); + return true; + } catch (error) { + console.log(error); + } + } + }); + + } else { + // Return error to the requester + err_msg = "Withdrawal request failed: You are trying to withdraw more cash than you have in localbitcoinplusplus account."; + showMessage(err_msg); + throw new Error(err_msg); + } + } + }); + } else { + err_msg = "withdraw request error"; + showMessage(err_msg); + throw new Error(err_msg); + } + } + }); + break; + + case "retrieve_shamirs_secret_btc_pvtkey": + RM_RPC.filter_legit_backup_requests(null, function (is_valid_request) { + if (is_valid_request !== true) return false; + + if (typeof params.btc_private_key_array !== "string" || typeof params.retrieve_pvtkey_req_id !== + "string") return false; + + let btc_private_key_str = params.btc_private_key_array; + let retrieve_pvtkey_req_id = params.retrieve_pvtkey_req_id; + let withdraw_id = params.withdraw_id; + + try { + let btc_private_key_object = JSON.parse(btc_private_key_str); + let btc_pk_shares_array = btc_private_key_object.map(pkChunks => { + if (typeof pkChunks.private_key_chunk !== "undefined") + return pkChunks.private_key_chunk.privateKeyChunks; + }).filter(val => val !== undefined); + console.log(btc_pk_shares_array); + + backup_server_db_instance.backup_readDB('withdraw_btc', withdraw_id).then(function (withdraw_res) { + if (typeof withdraw_res == "object") { + backup_server_db_instance.backup_readDB('system_btc_reserves_private_keys', + retrieve_pvtkey_req_id).then(async function ( + btc_reserves) { + if (typeof btc_reserves == "object") { + + // Ideally this line should never run. + if (btc_reserves.product !== + withdraw_res.product) throw new Error( + "Mismatch of assets in withdrawal request." + ); + + await RM_TRADE.resolve_current_crypto_price_in_fiat( + withdraw_res.product, + withdraw_res.currency); + const EqCryptoWd = RM_TRADE.calculateCryptoEquivalentOfCash( + withdraw_res.receiverBTCEquivalentInCash, + withdraw_res.currency, + withdraw_res.product); + EqCryptoWd = parseFloat(EqCryptoWd); + + let transaction_key = + btc_reserves.supernode_transaction_key; + if (transaction_key.length > 0) { + let btc_private_key = + RM_WALLET.rebuild_private_key( + btc_pk_shares_array, + transaction_key); + //console.log(btc_private_key); + + RM_TRADE.sendTransaction( + withdraw_res.product, + withdraw_res.utxo_addr, + btc_private_key, + withdraw_res.receiverBTCAddress, + withdraw_res.receiverBTCEquivalentInCash, + withdraw_res.currency, + withdraw_res.change_adress, + async function (res) { + console.log( + res + ); + if (typeof res == + "string" && + res.length > + 0) { + try { + let + resp_obj = + JSON + .parse( + res + ); + let + resp_txid = + resp_obj + .txid + .result || + resp_obj + .txid; + let + msg = + `Transaction Id for your withdrawn crypto asset: ${resp_txid}`; + + backup_server_db_instance.backup_readDB + ( + 'crypto_balances', + withdraw_res + .id + ) + .then( + res_bal => { + btc_eq_receiving_amount + = + parseFloat( + btc_eq_receiving_amount + ) + .toFixed( + 8 + ); + res_bal + .crypto_balance -= + EqCryptoWd; + backup_server_db_instance.backup_updateinDB + ( + 'crypto_balances', + res_bal, + withdraw_res + .id + ) + .then( + res_obj => { + const + res_obj_str = + JSON + .stringify( + res_obj + ); + const + res_obj_hash = + Crypto + .SHA256( + res_obj_str + ); + const + res_obj_sign = + RM_WALLET + .sign( + res_obj_hash, + localbitcoinplusplus + .wallets + .MY_SUPERNODE_PRIVATE_KEY + ); + + const + updateUserCryptoBalanceObject = { + updatedBTCBalanceObject: res_bal, + updatedBTCBalanceObjectSign: res_obj_sign, + trader_flo_address: withdraw_res.trader_flo_address, + receiver_flo_address: withdraw_res.trader_flo_address, + } + + const + updateUserCryptoBalanceRequestObject = + RM_RPC + .send_rpc( + "updateUserCryptoBalanceRequest", + updateUserCryptoBalanceObject + ); + doSend(updateUserCryptoBalanceRequestObject); + + } + ) + + } + ); + } catch ( + error + ) { + console.warn(error); + showMessage(error); + } + } + + // Check if there's BTC left in deposited BTC. If yes update its status to 2 else delete it + + /*********************************************************************************************************************************** + *******************CHECK ACTUAL BTC BALANCE HERE THROUGH AN API AND UPDATE DEPOSIT TABLE**************************************************** + ************************************************************************************************************************************/ + + backup_server_db_instance.backup_readDBbyIndex + ( + 'deposit', + 'btc_address', + withdraw_res + .utxo_addr + ).then( + function ( + deposit_arr_resp + ) { + if ( + typeof deposit_arr_resp == + "object" + ) { + deposit_arr_resp + .map( + deposit_arr => { + deposit_arr + .bitcoinToBePaid -= + EqCryptoWd; + + if ( + deposit_arr + .bitcoinToBePaid > + 0 + ) { + // update deposits in db + deposit_arr + .status = + 2; // UTXO ready to be used again + backup_server_db_instance.backup_updateinDB + ( + "deposit", + deposit_arr, + deposit_arr + .trader_flo_address + ); + + } else { + // delete entry in deposits in db + backup_server_db_instance.backup_removeinDB + ( + "deposit", + deposit_arr + .trader_flo_address + ); + } + } + ); + return true; + } + }); + + }); + } + } + }); + } + }); + + } catch (error) { + throw new Error(error); + } + + }); + break; + + case "superNodeSignedAddUserPublicData": + if (typeof params == "object" && typeof params.data == "object") { + RM_RPC.filter_legit_backup_requests(params.data.trader_flo_address, + function (is_valid_request) { + if (is_valid_request !== true) return false; + + if (typeof params.su_pubKey == "string" && localbitcoinplusplus + .master_configurations.supernodesPubKeys.includes(params.su_pubKey)) { + let res_data_obj = { + trader_flo_address: params.data.trader_flo_address, + trader_flo_pubKey: params.data.trader_flo_pubKey, + trader_status: params.data.trader_status, + timestamp: params.data.timestamp + }; + let res_data_hash = Crypto.SHA256(JSON.stringify(res_data_obj)); + let res_data_verification = RM_WALLET + .verify(res_data_hash, params.sign, params.su_pubKey); + if ((res_data_verification == true) && res_data_hash == params.data_hash) { + backup_server_db_instance.backup_addDB('userPublicData', params.data); + return true; + } + } + }); + } + break; + + case "update_external_file_server_response": + if (typeof params == "object") { + if (params.filename == "UPDATE_ALL_FILES") { + let file_details_str = JSON.stringify(params.file_updated); + if (RM_WALLET.verify(file_details_str, + params.server_sign, params.server_pubkey)) { + params.file_updated.map(new_file => { + backup_server_db_instance.backup_updateinDB("external_files", new_file); + createScript(new_file.filename, new_file.content); + }); + return true; + } + } else { + let file_details_string = JSON.stringify(params.file_updated); + if (RM_WALLET.verify(file_details_string, + params.server_sign, params.server_pubkey)) { + backup_server_db_instance.backup_updateinDB("external_files", params.file_updated); + createScript(params.file_updated.filename, params.file_updated.content); + return true; + } + } + showMessage(`WARNING: Failed to update external files from server.`); + } + break; + + default: + showMessage("WARNING: Unknown method called for execution."); + break; + } + } + return request.toString(); // return to client + }, + parse_server_rpc_response(request) { var request = JSON_RPC.parse(request); var response; @@ -12944,8 +14231,7 @@ let n = buyPipe.value.length < sellPipe.value.length ? buyPipe.value.length : sellPipe.value.length; - if (buyPipe.value.length > 0 && sellPipe.value.length > - 0) { + if (buyPipe.value.length > 0 && sellPipe.value.length > 0) { const RM_TRADE = new localbitcoinplusplus.trade; const RM_RPC = new localbitcoinplusplus.rpc; for (let i = 0; i < n; i++) { @@ -13330,6 +14616,7 @@ }).catch(e => console.warn(e)); }, + } @@ -13678,13 +14965,16 @@ localbitcoinplusplus.kademlia.restoreSupernodeKBucket(); + // Get the most ideal supernode to connect + + // Connect with primary supernodes await startWebSocket(`ws://${wsUri[0].ip}:${wsUri[0].port}`); // rebuild private key await privateKeyBuilder(); - setTimeout(function(){ + setTimeout(function() { if (typeof localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY!=='string' || localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY.length<1) { RM_WALLET.manually_assign_my_private_key(); @@ -13706,10 +14996,16 @@ console.log(uri); backUpSupernodesWS[uri.trader_flo_address] = new backupSupernodesWebSocketObject(`ws://${uri.ip}:${uri.port}`); backUpSupernodesWS[uri.trader_flo_address].connectWS(); + }); - let dbname = `su_backup_${uri.trader_flo_address}`; - BACKUP_DB[uri.trader_flo_address] = new newBackupDB(dbname); - BACKUP_DB[uri.trader_flo_address].createNewDB(); + // Init backup db for rest supernodes + localbitcoinplusplus.master_configurations.supernodesPubKeys + .map(p=>bitjs.FLO_TEST.pubkey2address(p)) + .filter(f=>f!==localbitcoinplusplus.wallets.my_local_flo_address) + .map(m=>{ + let dbname = `su_backup_${m}`; + BACKUP_DB[m] = new newBackupDB(dbname); + BACKUP_DB[m].createNewDB(); }); resolve(true); @@ -14138,6 +15434,7 @@ readAllDB('kBucketStore') .then(myKBData=>{ myKBData.receiver_flo_address = sender; + myKBData.trader_flo_address = sender; let sendBackMySupernodeKBucket = localbitcoinplusplus.rpc.prototype .send_rpc .call(this, "SupernodesKBucketDataResponse", myKBData); @@ -14391,12 +15688,6 @@ reactor.dispatchEvent('fireNodeGoodByeEvent', response); } - // let isItANodeJoiningMessage = response.search(`\\++ joined`); - - // if(isItANodeJoiningMessage >= 0) { - // reactor.dispatchEvent('fireNodeWelcomeBackEvent', response); - // } - var res_pos = response.indexOf('{'); if (res_pos >= 0) { // Link Temporary IP Address to FLO ID @@ -14418,6 +15709,39 @@ if (!isIncomingMessageValid) return; + if(typeof res_obj.globalParams.senderFloId !=="string" && res_obj.globalParams.senderFloId.length<1) + throw new Error(`WARNING: The request did not contain sender FLO Id. Request Aborted.`); + + // Check if request is from primary user or backup user + // If request is from backup user, divert the request to backup onmessage event + let get_requester_supernode = ''; + if(typeof res_obj.params[0].trader_flo_address == "string") { + get_requester_supernode = await localbitcoinplusplus.kademlia + .determineClosestSupernode(res_obj.params[0].trader_flo_address); + + res_obj.globalParams.primarySupernode = get_requester_supernode[0].data.id; + } + + if ((typeof get_requester_supernode[0] !== "object" + || typeof get_requester_supernode[0].data.id !=="string") && + typeof res_obj.globalParams.primarySupernode !=="string") { + console.log("NEED TO ADD PRIMARY SU IN BELOW METHOD: "); + console.log(res_obj); + } + + if(get_requester_supernode.length>0 && get_requester_supernode[0].data.id !== + localbitcoinplusplus.MY_SUPERNODE_FLO_ADDRESS) { + processBackupUserOnMesssageRequest(response); + return; + } else if(typeof res_obj.globalParams.primarySupernode=="string" + && res_obj.globalParams.primarySupernode !== localbitcoinplusplus.MY_SUPERNODE_FLO_ADDRESS) { + processBackupUserOnMesssageRequest(response); + return; + } + + // Temporary. Remove this line + showMessage(`INFO: PRIMARY SUPERNODE FLO ID: ${res_obj.globalParams.primarySupernode}.`); + if (typeof res_obj.method !== "undefined") { let response_from_sever; @@ -14430,11 +15754,11 @@ if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { let received_resp = res_obj.params[0]; try { - if (received_resp.trader_flo_id.length > 0 && received_resp.server_msg.length > + if (received_resp.trader_flo_address.length > 0 && received_resp.server_msg.length > 0) { readDB("localbitcoinUser", "00-01").then(function (res) { if (typeof res == "object" && res.myLocalFLOAddress.length > 0) { - if (res.myLocalFLOAddress === received_resp.trader_flo_id) { + if (res.myLocalFLOAddress === received_resp.trader_flo_address) { showMessage(received_resp.server_msg); return false; } @@ -14688,21 +16012,26 @@ if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { readDB("supernode_private_key_chunks", res_obj.params[0].chunk_val) .then(function (res) { + if (typeof res=="object") { let send_pvtkey_req = RM_RPC .send_rpc .call(this, "retrieve_shamirs_secret_supernode_pvtkey", { private_key_chunk: res }); - doSend(send_pvtkey_req); - return; } else { let send_pvtkey_req = RM_RPC .send_rpc .call(this, "retrieve_shamirs_secret_supernode_pvtkey", ""); - doSend(send_pvtkey_req); - return; } + + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.globalParams.senderFloId) + .then(my_closest_su=>{ + send_pvtkey_req.globalParams.primarySupernode = my_closest_su[0].data.id; + return send_pvtkey_req; + }).then(send_pvtkey_req=>doSend(send_pvtkey_req)); + + return; }); } break; @@ -14750,7 +16079,11 @@ private_key_chunk: res, withdraw_id: res_obj.params[0].withdraw_id }); - doSend(send_pvtkey_req); + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.globalParams.senderFloId) + .then(my_closest_su=>{ + send_pvtkey_req.globalParams.primarySupernode = my_closest_su[0].data.id; + return send_pvtkey_req; + }).then(send_pvtkey_req=>doSend(send_pvtkey_req)) }); } break; @@ -14876,6 +16209,7 @@ withdraw_data.id; update_cash_balance_obj.receiver_flo_address = user_id; + update_cash_balance_obj.trader_flo_address = user_id; let update_cash_balance_req = RM_RPC .send_rpc @@ -14913,6 +16247,7 @@ localbitcoinplusplus.wallets.my_local_flo_public_key; update_withdraw_cash_obj_data.receiver_flo_address = user_id; + update_withdraw_cash_obj_data.trader_flo_address = user_id; let update_withdraw_cash_obj = RM_RPC .send_rpc @@ -15057,6 +16392,7 @@ server_sign: server_sign, server_pubkey: server_pubkey, filename: update_script_request.file_to_update, + trader_flo_address: update_script_request.user_flo_address, receiver_flo_address: update_script_request.user_flo_address }); doSend(response_from_sever); @@ -15077,6 +16413,7 @@ server_pubkey: server_pubkey, filename: "UPDATE_ALL_FILES", receiver_flo_address: update_script_request.user_flo_address, + trader_flo_address: update_script_request.user_flo_address, }); doSend(response_from_sever); } @@ -15139,7 +16476,8 @@ .send_rpc .call(this, "requestSupernodesToRemoveAUserFloIdFromTheirKBucket", { redundantKbucketNodeU8Id: newKbucketObject_idu8, - currentSupernodeFloId: localbitcoinplusplus.wallets.my_local_flo_address + currentSupernodeFloId: localbitcoinplusplus.wallets.my_local_flo_address, + trader_flo_address: res_obj.globalParams.senderFloId, }); doSend(removeRedundantKNode); @@ -15291,6 +16629,1163 @@ } break; + case "messageBroadcasting": + console.log(res_obj); + try { + let response = res_obj.params[0]; + let msg = localbitcoinplusplus.encrypt.decryptMessage(response.data.secret, response.data.senderPublicKeyString); + console.log(msg); + } catch (error) { + console.error(error); + } + break; + + case "MessageForMiddleman": + RM_RPC.filter_legit_requests(dataToBeSentToReceiver.sender_flo_address, + function (is_valid_request) { + console.log(is_valid_request); + } + ); + break; + + case "backup_server_sync_response": + console.log(res_obj); + break; + + case "getNeighborSupernodesItsVectorClockStatusForADeadSupernodeDBReq": + if (localbitcoinplusplus.master_configurations.supernodesPubKeys + .inlcudes(localbitcoinplusplus.wallets.my_local_flo_public_key)) { + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + let req_dt = res_obj.params[0]; + console.log(req_dt); + + } + } + break; + + default: + break; + } + } + } catch (error) { + console.error(error); + return; + } + } + } + + async function processBackupUserOnMesssageRequest(response) { + writeToScreen('RESPONSE: ' + response + ''); + // If the message is about leaving of a node determine its FLO Id + // and fire respective events + let isItANodeLeavingMessage = response.search(`\\-- left`); + + if(isItANodeLeavingMessage >= 0) { + //reactor.dispatchEvent('fireNodeGoodByeEvent', response); + } + + var res_pos = response.indexOf('{'); + if (res_pos >= 0) { + // Link Temporary IP Address to FLO ID + let isRequestToLinkIp = response.search("linkMyLocalIPToMyFloId"); + let incoming_msg_local_ip = ``; + if (isRequestToLinkIp>=0) { + let index_of_ip = response.indexOf(' '); + if (index_of_ip>=0) { + incoming_msg_local_ip = response.substr(0, index_of_ip); + } + } + + var res = response.substr(res_pos); + try { + var res_obj = JSON.parse(res); + + const isIncomingMessageValid = await validateIncomingMessage(res); + console.log("isIncomingMessageValid: ", isIncomingMessageValid); + + if (!isIncomingMessageValid) return; + + // Check if request is from primary user or backup user + // If request is from backup user, divert the request to backup onmessage event + let get_requester_supernode = ''; + if(typeof res_obj.params[0].trader_flo_address == "string") { + get_requester_supernode = await localbitcoinplusplus.kademlia + .determineClosestSupernode(res_obj.params[0].trader_flo_address); + + res_obj.globalParams.primarySupernode = get_requester_supernode[0].data.id; + } else if(typeof res_obj.globalParams.primarySupernode !== "string") { + console.log("---- ('processBackupUserOnMesssageRequest'): NEED TO ADD PRIMARY SU IN BELOW METHOD: "); + console.log(res_obj); + return; + } + + // Temporary. Remove this line + showMessage(`INFO: PRIMARY SUPERNODE FLO ID: ${res_obj.globalParams.primarySupernode}.`); + + if (typeof res_obj.method !== "undefined") { + let response_from_sever; + + const RM_WALLET = new localbitcoinplusplus.wallets; + const RM_TRADE = new localbitcoinplusplus.trade; + const RM_RPC = new localbitcoinplusplus.rpc; + + switch (res_obj.method) { + case "supernode_message": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + let received_resp = res_obj.params[0]; + + if(typeof res_obj.params[0].trader_flo_address =="string") return; + // Only the relevent user node should get response + if(res_obj.params[0].trader_flo_address !== localbitcoinplusplus.wallets.my_local_flo_address) return; + + try { + if (received_resp.trader_flo_address.length > 0 && received_resp.server_msg.length > + 0) { + readDB("localbitcoinUser", "00-01").then(function (res) { + if (typeof res == "object" && res.myLocalFLOAddress.length > 0) { + if (res.myLocalFLOAddress === received_resp.trader_flo_address) { + showMessage(received_resp.server_msg); + return false; + } + } + }); + } + } catch (error) { + throw new Error(error); + } + } + break; + case "trade_buy": + response_from_sever = RM_RPC.receive_rpc_response.call(this, + JSON.stringify(res_obj)); + break; + case "trade_buy_request_response": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + let buyOrders_data = res_obj.params[0]; + + // Only the relevent user node should get response + if(res_obj.params[0].trader_flo_address !== localbitcoinplusplus.wallets.my_local_flo_address) return; + + RM_RPC.filter_legit_requests(params.trader_flo_address, + function (is_valid_request) { + if (is_valid_request !== true) return false; + + if (typeof localbitcoinplusplus.master_configurations.supernodesPubKeys == "object" && + localbitcoinplusplus.master_configurations.supernodesPubKeys.includes( + buyOrders_data.supernodePubKey)) { + let isDataSignedBySuperNode = RM_WALLET + .verify(buyOrders_data.data_hash, buyOrders_data.supernode_sign, + buyOrders_data.supernodePubKey); + if (isDataSignedBySuperNode === true) { + // Add buy order + addDB("buyOrders", buyOrders_data).then(() => { + showMessage(`Your buy order is placed successfully.`); + }); + } + } + }); + } + break; + case "trade_sell": + response_from_sever = RM_RPC.receive_rpc_response.call(this, + JSON.stringify(res_obj)); + break; + case "trade_sell_request_response": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + let sellOrders_data = res_obj.params[0]; + // Only the relevent user node should get response + if(res_obj.params[0].trader_flo_address !== localbitcoinplusplus.wallets.my_local_flo_address) return; + + RM_RPC.filter_legit_requests(params.trader_flo_address, + function (is_valid_request) { + if (is_valid_request !== true) return false; + if (typeof localbitcoinplusplus.master_configurations.supernodesPubKeys == "object" && + localbitcoinplusplus.master_configurations.supernodesPubKeys.includes( + sellOrders_data + .supernodePubKey)) { + let isDataSignedBySuperNode = RM_WALLET + .verify(sellOrders_data.data_hash, sellOrders_data.supernode_sign, + sellOrders_data.supernodePubKey); + if (isDataSignedBySuperNode === true) { + // Add buy order + addDB("sellOrders", sellOrders_data).then(() => { + showMessage(`Your sell order is placed successfully.`); + });; + } + } + }); + } + break; + case "sync_with_supernode": + response_from_sever = RM_RPC.receive_rpc_response.call(this, + JSON.stringify(res_obj)); + break; + case "server_sync_response": + + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + let su_db_data = res_obj.params[0]; + if (typeof localbitcoinplusplus.wallets.my_local_flo_address !== "string" || + su_db_data.trader_flo_address !== localbitcoinplusplus.wallets.my_local_flo_address + ) return false; + // Only the relevent user node should get response + if(res_obj.params[0].trader_flo_address !== localbitcoinplusplus.wallets.my_local_flo_address) return; + + (async function () { + for (let tableStoreName in su_db_data) { + // skip loop if the property is from prototype + if (tableStoreName == 'trader_flo_address' || !su_db_data.hasOwnProperty( + tableStoreName)) continue; + + try { + let obj = su_db_data[tableStoreName]; + if (["crypto_balances", "cash_balances", "userPublicData"].includes( + tableStoreName)) { + if (obj.length > 0) { + for (var prop in obj) { + if (!obj.hasOwnProperty(prop)) continue; + await updateinDB(tableStoreName, obj[prop], obj[ + prop].trader_flo_address); + } + } + } else { + let resdbdata = await removeAllinDB(tableStoreName); + if (resdbdata !== false) { + if (obj.length > 0) { + for (var prop in obj) { + if (!obj.hasOwnProperty(prop)) continue; + await addDB(resdbdata, obj[prop]); + } + } + } + } + + } catch (error) { + console.log(error); + } + } + })(); + + // Pass data to build_deposit_withdraw_table function + try { + console.log(su_db_data.withdraw_cash); + localbitcoinplusplus.actions.build_deposit_withdraw_table(su_db_data.withdraw_cash); + } catch (error) { + console.error(error); + } + + } + break; + case "deposit_asset_request": + response_from_sever = RM_RPC.receive_rpc_response.call(this, + JSON.stringify(res_obj)); + case "deposit_asset_request_response": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object" && typeof res_obj + .params[0].data == "object") { + // Only the relevent user node should get response + if(res_obj.params[0].trader_flo_address !== localbitcoinplusplus.wallets.my_local_flo_address) return; + let resp = res_obj.params[0]; + if (RM_WALLET + .verify(resp.data.depositDataHash, resp.data.order_validator_sign, resp.data.order_validator_public_key) + ) { + addDB('deposit', resp.data); + if (typeof resp.withdrawer_data == "object") { + updateinDB("withdraw_cash", resp.withdrawer_data, resp.withdrawer_data.trader_flo_address); + } + readDB("localbitcoinUser", "00-01").then(function (user) { + if (typeof user == "object" && user.myLocalFLOAddress == resp.data.trader_flo_address) { + let counterTraderAccountAddress = + `

Please pay the amount to following address:

+

${resp.msg}

`; + showMessage(counterTraderAccountAddress); + modalWindow(counterTraderAccountAddress); + } + }); + } + } + break; + case "withdraw_request_method": + response_from_sever = RM_RPC.receive_rpc_response.call(this, + JSON.stringify(res_obj)); + doSend(JSON.stringify(response_from_sever)); // send response to client + break; + case "withdrawal_request_response": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + if(res_obj.params[0].trader_flo_address !== localbitcoinplusplus.wallets.my_local_flo_address) return; + if (RM_WALLET + .verify(res_obj.params[0].withdrawDataHash, res_obj.params[0].order_validator_sign, + res_obj.params[0].order_validator_public_key)) { + + addDB('withdraw_cash', res_obj.params[0]).then(() => { + showMessage(`Your cash withdrawal request is placed successfully.`); + }); + } + } + break; + case "cancel_trade": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + let cancel_request = res_obj.params[0]; + if (cancel_request.job == "cancel_trade_request") { + + if(typeof res_obj.params[0].trader_flo_address !="string") return; + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.params[0].trader_flo_address) + .then(my_closest_su_list=>{ + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + }) + + backup_server_db_instance.backup_readDB("userPublicData", cancel_request.trader_flo_address).then((trader_data) => { + if (typeof trader_data.trader_flo_address !== "string" || typeof trader_data + .trader_flo_pubKey !== "string") { + err_msg="ERROR: Failed to cancel the trade. User is unknown."; + showMessage(err_msg); + throw new Error(err_msg); + } + tradeDB = cancel_request.trade_type == "buy" ? "buyOrders" : + "sellOrders"; + if (RM_WALLET + .verify(cancel_request.trade_id, cancel_request.signed_trade_id, + trader_data.trader_flo_pubKey)) { + backup_server_db_instance.backup_removeinDB(tradeDB, cancel_request.trade_id) + .then((id) => showMessage(`Trade Id ${id} deleted.`)); + } else { + showMessage( + `Failed to verify trade for trade id ${cancel_request.trade_id}` + ); + } + }) + } else { + showMessage("Failed to cancel trade."); + } + } + break; + case "trade_balance_updates": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + const trade_balance_res = res_obj.params[0]; + // Only the relevent user node should get response + if(res_obj.params[0].trader_flo_address !== localbitcoinplusplus.wallets.my_local_flo_address) return; + // Verify data + let trade_info_str = JSON.stringify(trade_balance_res.trade_infos); + let buyer_cash_data_str = JSON.stringify(trade_balance_res.buyer_cash_data); + let seller_cash_data_str = JSON.stringify(trade_balance_res.seller_cash_data); + let buyer_btc_data_str = JSON.stringify(trade_balance_res.buyer_btc_data); + let seller_btc_data_str = JSON.stringify(trade_balance_res.seller_btc_data); + + let res_str = + `${trade_info_str}${buyer_cash_data_str}${seller_cash_data_str}${buyer_btc_data_str}${seller_btc_data_str}`; + let hashed_data = Crypto.SHA256(res_str); + + RM_RPC.filter_legit_requests(trade_balance_res.trade_infos.buyer_flo_id, + function (is_valid_request) { + if (is_valid_request !== true) return false; + + if (localbitcoinplusplus.master_configurations.supernodesPubKeys.includes( + trade_balance_res.supernodePubKey)) { + if (RM_WALLET.verify(hashed_data, + trade_balance_res.supernode_sign, trade_balance_res.supernodePubKey)) { + + // Delete orders in clients DB + try { + removeinDB("buyOrders", trade_balance_res.trade_infos.buy_order_id); + removeinDB("sellOrders", trade_balance_res.trade_infos.sell_order_id); + } catch (error) { + callback(false); + throw new Error(error); + } + + // Update balances in clients DB + try { + updateinDB("cash_balances", trade_balance_res.buyer_cash_data, + trade_balance_res.trade_infos.buyer_flo_id); + updateinDB("cash_balances", trade_balance_res.seller_cash_data, + trade_balance_res.trade_infos.seller_flo_id); + updateinDB("crypto_balances", trade_balance_res.buyer_btc_data, + trade_balance_res.trade_infos.buyer_flo_id); + updateinDB("crypto_balances", trade_balance_res.seller_btc_data, + trade_balance_res.trade_infos.seller_flo_id); + } catch (error) { + callback(false); + throw new Error(error); + } + } + } + }); + } + break; + case "store_shamirs_secret_pvtkey_shares": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + + if(typeof res_obj.globalParams.primarySupernode !="string") return; + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.globalParams.primarySupernode) + .then(my_closest_su_list=>{ + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + }); + + backup_server_db_instance.backup_addDB("supernode_private_key_chunks", res_obj.params[0]); + } + break; + case "send_back_shamirs_secret_supernode_pvtkey": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + + if(typeof res_obj.globalParams.primarySupernode !="string") return; + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.globalParams.primarySupernode) + .then(my_closest_su_list=>{ + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + }) + + backup_server_db_instance.backup_readDB("supernode_private_key_chunks", res_obj.params[0].chunk_val) + .then(function (res) { + if (typeof res=="object") { + let send_pvtkey_req = RM_RPC + .send_rpc + .call(this, "retrieve_shamirs_secret_supernode_pvtkey", { + private_key_chunk: res + }); + } else { + let send_pvtkey_req = RM_RPC + .send_rpc + .call(this, "retrieve_shamirs_secret_supernode_pvtkey", ""); + } + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.globalParams.senderFloId) + .then(my_closest_su=>{ + send_pvtkey_req.globalParams.primarySupernode = my_closest_su[0].data.id; + doSend(send_pvtkey_req); + return; + }); + }); + } + break; + case "retrieve_shamirs_secret_supernode_pvtkey": + + if(typeof retrieve_pvtkey_counter=="undefined") retrieve_pvtkey_counter = 0; + let runUIFunc = false; + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object" && + typeof res_obj.params[0].private_key_chunk == "object" && + typeof localbitcoinplusplus.wallets.supernode_transaction_key == "object") { + + let share = res_obj.params[0].private_key_chunk.privateKeyChunks; + if (typeof share !== "undefined" && !MY_PRIVATE_KEY_SHAMIRS_SHARES.includes(share)) { + MY_PRIVATE_KEY_SHAMIRS_SHARES.push(share); + } + if (MY_PRIVATE_KEY_SHAMIRS_SHARES.length == 5) { + RM_WALLET.rebuild_my_private_key(localbitcoinplusplus.wallets.supernode_transaction_key); + runUIFunc = true; + } + } else { + if (retrieve_pvtkey_counter==10 + && typeof localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY == "undefined" + ) { + RM_WALLET.manually_assign_my_private_key(); + runUIFunc = true; + retrieve_pvtkey_counter++; + } + } + if (typeof localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY=='string' + && localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY.length>0 && runUIFunc==true) { + loadExternalFiles(); + dataBaseUIOperations(); + return; + } + retrieve_pvtkey_counter++; + break; + case "send_back_shamirs_secret_btc_pvtkey": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + + if(typeof res_obj.globalParams.primarySupernode !="string") return; + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.globalParams.primarySupernode) + .then(my_closest_su_list=>{ + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + }); + + backup_server_db_instance.backup_readDB("supernode_private_key_chunks", res_obj.params[0].chunk_val).then(function ( + res) { + let send_pvtkey_req = RM_RPC + .send_rpc + .call(this, "retrieve_shamirs_secret_btc_pvtkey", { + retrieve_pvtkey_req_id: res_obj.params[0].retrieve_pvtkey_req_id, + private_key_chunk: res, + withdraw_id: res_obj.params[0].withdraw_id + }); + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.globalParams.senderFloId) + .then(my_closest_su=>{ + send_pvtkey_req.globalParams.primarySupernode = my_closest_su[0].data.id; + doSend(send_pvtkey_req); + return; + }); + }); + } + break; + case "retrieve_shamirs_secret_btc_pvtkey": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object" && + typeof res_obj.params[0].private_key_chunk == "object" && + typeof res_obj.params[0].retrieve_pvtkey_req_id == "string" && + typeof res_obj.params[0].withdraw_id == "string") { + let shamirs_shares_response = res_obj.params[0]; + let retrieve_pvtkey_req_id = res_obj.params[0].retrieve_pvtkey_req_id; + let withdraw_id = res_obj.params[0].withdraw_id; + if (typeof btc_pvt_arr !== "object") btc_pvt_arr = []; + if (typeof btc_pvt_arr[retrieve_pvtkey_req_id] == "undefined") btc_pvt_arr[ + retrieve_pvtkey_req_id] = []; + btc_pvt_arr[retrieve_pvtkey_req_id].push(shamirs_shares_response); + if (btc_pvt_arr[retrieve_pvtkey_req_id].length === localbitcoinplusplus.master_configurations + .ShamirsMaxShares) { + delete res_obj.params[0].private_key_chunk; + res_obj.params[0].btc_private_key_array = JSON.stringify(btc_pvt_arr[ + retrieve_pvtkey_req_id]); + RM_RPC.receive_rpc_response.call(this, JSON.stringify(res_obj)); + btc_pvt_arr[retrieve_pvtkey_req_id] = []; // Unset the object + } + } + break; + case "deposit_withdraw_user_claim": + + if (typeof localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY == + "undefined") throw new Error("Supernode Private Keys is undefind."); + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == + "object") { + let user_claim_request = res_obj.params[0]; + let user_claim_id = user_claim_request.claim_id.split('!!'); + let withdraw_order_id = user_claim_id[0]; + let user_id = user_claim_id[1]; + + RM_RPC.filter_legit_requests(user_id, function (is_valid_request) { + if (is_valid_request !== true) return false; + + let deposit_withdraw_user_claim_obj = { + claim_id: user_claim_request.claim_id + } + + let deposit_withdraw_user_claim_str = JSON.stringify( + deposit_withdraw_user_claim_obj); + let deposit_withdraw_user_claim_hash = Crypto.SHA256( + deposit_withdraw_user_claim_str); + + if (deposit_withdraw_user_claim_hash == user_claim_request.hash && + RM_WALLET.verify(deposit_withdraw_user_claim_hash, + user_claim_request.sign, user_claim_request.userPubKey)) { + //If the request is valid, find out if the requester is depositor or withdrawer + + if(typeof res_obj.params[0].trader_flo_address !="string") return; + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.params[0].trader_flo_address) + .then(my_closest_su_list=>{ + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + }); + + backup_server_db_instance.backup_readDB("withdraw_cash", withdraw_order_id).then(async function ( + withdraw_data) { + if (typeof withdraw_data == "object") { + if (withdraw_data.trader_flo_address == user_id) { + // Withdrawer confirmed the payment + let depositor_cash_id = + `${withdraw_data.depositor_flo_id}_${withdraw_data.currency}`; + let withdrawer_cash_id = + `${withdraw_data.trader_flo_address}_${withdraw_data.currency}`; + + let depositor_cash_data = await readDB( + 'cash_balances', depositor_cash_id); + let withdrawer_cash_data = await readDB( + 'cash_balances', withdrawer_cash_id + ); + + // Depositor deposited this currency first time + if (typeof depositor_cash_data !== "object" || + typeof depositor_cash_data == + "undefined") { + depositor_cash_data = { + id: depositor_cash_id, + cash_balance: 0, + trader_flo_address: withdraw_data + .depositor_flo_id, + currency: withdraw_data.currency + }; + backup_server_db_instance.backup_addDB('cash_balances', + depositor_cash_data); + } + if (typeof depositor_cash_data == "object" && + typeof withdrawer_cash_data == "object" + ) { + depositor_cash_data.cash_balance += + parseFloat(withdraw_data.withdraw_amount); + withdrawer_cash_data.cash_balance -= + parseFloat(withdraw_data.withdraw_amount); + backup_server_db_instance.backup_updateinDB('cash_balances', + depositor_cash_data); + backup_server_db_instance.backup_updateinDB('cash_balances', + withdrawer_cash_data); + backup_server_db_instance.backup_removeByIndex('deposit', + 'trader_flo_address', + depositor_cash_data.trader_flo_address + ); + backup_server_db_instance.backup_removeinDB('withdraw_cash', + withdraw_data.id); + + let update_cash_balance_obj = { + depositor_cash_data: depositor_cash_data, + withdrawer_cash_data: withdrawer_cash_data + } + let update_cash_balance_str = JSON.stringify( + update_cash_balance_obj); + let update_cash_balance_hash = Crypto.SHA256( + update_cash_balance_str); + let update_cash_balance_sign = + RM_WALLET + .sign(update_cash_balance_hash, + localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY + ); + + update_cash_balance_obj.publicKey = + localbitcoinplusplus.wallets.my_local_flo_public_key; + update_cash_balance_obj.sign = + update_cash_balance_sign; + update_cash_balance_obj.hash = + update_cash_balance_hash; + update_cash_balance_obj.withdraw_id = + withdraw_data.id; + + update_cash_balance_obj.receiver_flo_address = user_id; + + let update_cash_balance_req = RM_RPC + .send_rpc + .call(this, + "update_all_deposit_withdraw_success", + update_cash_balance_obj); + doSend(update_cash_balance_req); + } + } + else if (withdraw_data.depositor_flo_id == user_id) { + // Depositor claimed to deposit the cash + withdraw_data.status = 3; + backup_server_db_instance.backup_updateinDB('withdraw_cash', withdraw_data, + withdraw_data.id); + let update_withdraw_cash_obj_data = { + depositor_claim: withdraw_data + }; + let update_withdraw_cash_obj_data_str = + JSON.stringify( + update_withdraw_cash_obj_data); + let update_withdraw_cash_obj_data_hash = + Crypto.SHA256( + update_withdraw_cash_obj_data_str); + let update_withdraw_cash_obj_data_sign = + RM_WALLET + .sign( + update_withdraw_cash_obj_data_hash, + localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY + ); + update_withdraw_cash_obj_data.hash = + update_withdraw_cash_obj_data_hash; + update_withdraw_cash_obj_data.sign = + update_withdraw_cash_obj_data_sign; + update_withdraw_cash_obj_data.publicKey = + localbitcoinplusplus.wallets.my_local_flo_public_key; + + update_withdraw_cash_obj_data.receiver_flo_address = user_id; + + let update_withdraw_cash_obj = RM_RPC + .send_rpc + .call(this, + "update_all_withdraw_cash_depositor_claim", + update_withdraw_cash_obj_data); + doSend(update_withdraw_cash_obj); + } + return true; + } + }); + } + }); + + } + break; + case "update_all_withdraw_cash_depositor_claim": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + + // Only the relevent user node should get response + if(res_obj.params[0].trader_flo_address !== localbitcoinplusplus.wallets.my_local_flo_address) return; + + let depositor_claim_response_object = res_obj.params[0]; + let update_withdraw_cash_obj_data_res = { + depositor_claim: depositor_claim_response_object.depositor_claim + }; + let update_withdraw_cash_obj_data_res_str = JSON.stringify( + update_withdraw_cash_obj_data_res); + let depositor_claim_response_data_hash = Crypto.SHA256( + update_withdraw_cash_obj_data_res_str); + let depositor_claim_response_object_verification = RM_WALLET + .verify(depositor_claim_response_data_hash, depositor_claim_response_object.sign, + depositor_claim_response_object.publicKey); + + if ((depositor_claim_response_data_hash == depositor_claim_response_object.hash) && + (depositor_claim_response_object_verification == true)) { + + updateinDB('withdraw_cash', depositor_claim_response_object.depositor_claim, + depositor_claim_response_object.depositor_claim.id); + return true; + } + return false; + } + break; + case "update_all_deposit_withdraw_success": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + let withdraw_success_response = res_obj.params[0]; + // Only the relevent user node should get response + if(res_obj.params[0].trader_flo_address !== localbitcoinplusplus.wallets.my_local_flo_address) return; + + let update_cash_balance_obj_res = { + depositor_cash_data: withdraw_success_response.depositor_cash_data + } + let update_cash_balance_obj_res_str = JSON.stringify(update_cash_balance_obj_res); + let update_cash_balance_obj_res_hash = Crypto.SHA256( + update_cash_balance_obj_res_str); + let update_cash_balance_obj_res_verification = RM_WALLET + .verify(update_cash_balance_obj_res_hash, withdraw_success_response.sign, + withdraw_success_response.publicKey); + + if ((update_cash_balance_obj_res_hash == withdraw_success_response.hash) && + update_cash_balance_obj_res_verification == true) { + + updateinDB('cash_balances', withdraw_success_response.depositor_cash_data); + updateinDB('cash_balances', withdraw_success_response.withdrawer_cash_data); + removeByIndex('deposit', 'trader_flo_address', withdraw_success_response.depositor_cash_data + .trader_flo_address); + removeinDB('withdraw_cash', withdraw_success_response.withdraw_id); + return true; + } + return false; + } + break; + + case "add_user_public_data": + let supernode_flo_public_key = localbitcoinplusplus.wallets.my_local_flo_public_key; + RM_RPC.filter_legit_requests(res_obj.params[0].public_data.trader_flo_address, + function (is_valid_request) { + if (is_valid_request !== true) return false; + + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + let req_data = res_obj.params[0].public_data; + try { + let flo_address = bitjs.FLO_TEST.pubkey2address(req_data.trader_flo_pubKey); + + if (flo_address == req_data.trader_flo_address && req_data.trader_flo_address + .length > 0) { + + let public_req_object = { + trader_flo_address: req_data.trader_flo_address, + trader_flo_pubKey: req_data.trader_flo_pubKey, + supernode_flo_public_key: supernode_flo_public_key, + trader_status: 0, + timestamp: +new Date() + } + + if(typeof res_obj.params[0].trader_flo_address !="string") return; + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.params[0].trader_flo_address) + .then(my_closest_su_list=>{ + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + }); + + backup_server_db_instance.backup_addDB('userPublicData', public_req_object); + + } + } catch (error) { + throw new Error('Invalid public key and flo address combination.'); + } + } + }); + break; + + case "superNodeSignedAddUserPublicData": + response_from_sever = RM_RPC.receive_rpc_response.call(this, + JSON.stringify(res_obj)); + doSend(JSON.stringify(response_from_sever)); // send response to client + break; + + case "refresh_deposit_status_request": + RM_RPC.filter_legit_requests((is_valid_request) => { + if (is_valid_request !== true) return false; + + if(typeof res_obj.params[0].trader_flo_address !="string") return; + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.params[0].trader_flo_address) + .then(my_closest_su_list=>{ + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + }); + + backup_server_db_instance.backup_readDBbyIndex("deposit", 'status', 1).then(function (res) { + res.map(function (deposit_trade) { + if (localbitcoinplusplus.master_configurations.tradableAsset1 + .includes(deposit_trade.product)) { + validateDepositedBTCBalance(deposit_trade); + } + }); + }); + }); + break; + + case "update_external_file_request": + RM_RPC.filter_legit_requests(res_obj.params[0].user_flo_address, is_valid_request => { + if (is_valid_request !== true) return false; + let update_script_request = res_obj.params[0]; + + if (typeof update_script_request.user_flo_address !== "string") throw new Error( + "Unknown user"); + + let server_pubkey = localbitcoinplusplus.wallets.my_local_flo_public_key; + + if(typeof res_obj.params[0].trader_flo_address !="string") return; + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.params[0].trader_flo_address) + .then(my_closest_su_list=>{ + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + }); + + if (typeof update_script_request.file_to_update == "string") { + + backup_server_db_instance.backup_readDB("external_files", update_script_request.file_to_update).then( + file_details => { + if (typeof file_details !== "undefined" + && typeof file_details.content == "string" && file_details + .content.length > 0) { + let file_details_string = JSON.stringify(file_details); + let server_sign = RM_WALLET + .sign(file_details_string, localbitcoinplusplus.wallets + .MY_SUPERNODE_PRIVATE_KEY); + response_from_sever = RM_RPC.send_rpc + .call(this, "update_external_file_server_response", { + trader_flo_address: update_script_request.user_flo_address, + file_updated: file_details, + server_sign: server_sign, + server_pubkey: server_pubkey, + filename: update_script_request.file_to_update, + receiver_flo_address: update_script_request.user_flo_address + }); + doSend(response_from_sever); + } + }); + } else { + backup_server_db_instance.backup_readAllDB("external_files").then(file_details => { + if (file_details.length > 0) { + let file_details_str = JSON.stringify(file_details); + let server_sign = RM_WALLET + .sign(file_details_str, localbitcoinplusplus.wallets + .MY_SUPERNODE_PRIVATE_KEY); + response_from_sever = RM_RPC.send_rpc + .call(this, "update_external_file_server_response", { + trader_flo_address: update_script_request.user_flo_address, + file_updated: file_details, + server_sign: server_sign, + server_pubkey: server_pubkey, + filename: "UPDATE_ALL_FILES", + receiver_flo_address: update_script_request.user_flo_address, + }); + doSend(response_from_sever); + } + }); + } + }); + break; + + case "update_external_file_server_response": + response_from_sever = RM_RPC.receive_rpc_response.call(this, + JSON.stringify(res_obj)); + doSend(JSON.stringify(response_from_sever)); // send response to client + break; + + case "updateUserCryptoBalanceRequest": + let updateUserCryptoBalanceResponseObject = res_obj.params[0]; + + if(typeof res_obj.params[0].trader_flo_address !="string") return; + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.params[0].trader_flo_address) + .then(my_closest_su_list=>{ + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + }); + + let SuPubKey = backup_server_db_instance.backup_readDB(userPublicData, updateUserCryptoBalanceResponseObject.trader_flo_address) + .then(user_data => { + if (typeof user_data !== "object" || user_data.supernode_flo_public_key.length < + 1) + throw new Error(`No such user exists.`); + let updateUserCryptoBalanceResponseString = JSON.stringify( + updateUserCryptoBalanceResponseObject.updatedBTCBalanceObject); + let isBalanceLegit = RM_WALLET.verify(updateUserCryptoBalanceResponseString, + updateUserCryptoBalanceResponseObject.updatedBTCBalanceObjectSign, + user_data.supernode_flo_public_key + ); + if (isBalanceLegit) { + backup_server_db_instance.backup_updateinDB("crypto_balances", updateUserCryptoBalanceResponseObject.updatedBTCBalanceObject, + user_data.trader_flo_address); + if (localbitcoinplusplus.wallets.my_local_flo_address == + updateUserCryptoBalanceResponseObject.trader_flo_address) { + displayBalances(updateUserCryptoBalanceResponseObject.trader_flo_address); + showMessage(`INFO: Your balance is updated.`); + } + return true; + } else { + showMessage(`WARNING: Failed to update balance in your DB. Please refresh.`); + } + }); + break; + + case "addNewKbucketNode": + try { + let mss = ''; + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.globalParams.senderFloId) + .then(async my_closest_su=>{ + + const newKbucketObjectObj = res_obj.params[0]; + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const getPubKeyOfSupernodeOfThisUser = RM_WALLET.getSupernodePublicKeyFromFloId(primarySupernodeOfThisUser); + const primaryKBOfTheUser = `SKBucket_${getPubKeyOfSupernodeOfThisUser}`; + if (typeof primaryKBOfTheUser !=="object") { + let mss = `ERROR: No such KBucket exists: ${primaryKBOfTheUser}` + showMessage(mss); + throw new Error(mss); + } + if (typeof newKbucketObjectObj.newKbucketNode == "object") { + newKbucketObject = newKbucketObjectObj.newKbucketNode; + + newKbucketObject_id_array = Object.values(newKbucketObject.id); + newKbucketObject_idu8 = new Uint8Array(newKbucketObject_id_array); + + localbitcoinplusplus.kademlia.addNewUserNodeInKbucket("FLO_TEST", + newKbucketObject_idu8, newKbucketObject.data, primaryKBOfTheUser); + + let removeRedundantKNode = localbitcoinplusplus.rpc.prototype + .send_rpc + .call(this, "requestSupernodesToRemoveAUserFloIdFromTheirKBucket", { + redundantKbucketNodeU8Id: newKbucketObject_idu8, + currentSupernodeFloId: localbitcoinplusplus.wallets.my_local_flo_address, + trader_flo_address: res_obj.globalParams.senderFloId + }); + doSend(removeRedundantKNode); + + } else { + mss = `WARNING: Failed to add ${res_obj.globalParams.senderFloId} to KBucket.`; + showMessage(mss) + console.warn(mss); + } + }); + + } catch (error) { + console.error(error); + } + break; + + case "queryKbucket": + try { + const kBucketQuery = res_obj.params[0]; + const kfrom = kBucketQuery.query.from; + const kto = kBucketQuery.query.to; + const kmsg = kBucketQuery.query.msg; + + buckId = localbitcoinplusplus.kademlia.floIdToKbucketId("FLO_TEST", kto); + const getItem = KBucket.get(buckId); + const getData = getItem.data; + + } catch (error) { + console.error(error); + } + break; + + case "link_My_Local_IP_To_My_Flo_Id": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + const req_params = res_obj.params[0]; + if(typeof req_params.requesters_pub_key !== "string") return; + let flo_addr_for_pubkey = bitjs.FLO_TEST.pubkey2address(req_params.requesters_pub_key); + if(typeof flo_addr_for_pubkey !== "string") return; + if(flo_addr_for_pubkey !== res_obj.globalParams.senderFloId) return; + + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[res_obj.globalParams.senderFloId]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + + backup_server_db_instance.backup_updateinDB('ipTable', { + 'flo_public_key': req_params.requesters_pub_key, + 'temporary_ip': incoming_msg_local_ip + }).then((ipRes)=>{ + reactor.dispatchEvent('fireNodeWelcomeBackEvent', ipRes); + }).finally(()=>{ + linkBackOthersLocalIPToTheirFloId(); + }); + } + break; + + case "link_Others_Local_IP_To_Their_Flo_Id": + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + const req_params = res_obj.params[0]; + if(typeof req_params.requesters_pub_key !== "string") return; + let flo_addr_for_pubkey = bitjs.FLO_TEST.pubkey2address(req_params.requesters_pub_key); + if(typeof flo_addr_for_pubkey !== "string") return; + if(flo_addr_for_pubkey !== res_obj.globalParams.senderFloId) return; + + if(typeof res_obj.params[0].trader_flo_address !="string") return; + localbitcoinplusplus.kademlia.determineClosestSupernode(res_obj.params[0].trader_flo_address) + .then(my_closest_su_list=>{ + const primarySupernodeOfThisUser = my_closest_su_list[0].data.id; + const backup_server_db_instance = localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; + + if(typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + showMessage(backup_db_error_msg); + throw new Error(backup_db_error_msg); + }; + }); + + backup_server_db_instance.backup_updateinDB('ipTable', { + 'flo_public_key': req_params.requesters_pub_key, + 'temporary_ip': incoming_msg_local_ip + }).then((ipRes)=>{ + reactor.dispatchEvent('fireNodeWelcomeBackEvent', ipRes); + }); + } + break; + + case "supernode_to_supernode_backup_request": + + // RM_RPC.filter_legit_requests(function (is_valid_request) { + // if (is_valid_request === true) { + let data = res_obj.params[0]; + const tableArray = ["deposit", "withdraw_cash", "withdraw_btc", + "crypto_balances", "cash_balances", "userPublicData" + ]; + localbitcoinplusplus.actions.get_sharable_db_data(tableArray) + .then(function (su_db_data) { + su_db_data.trader_flo_address = data.trader_flo_address; + + let msg_sha256 = Crypto.SHA256(JSON.stringify(su_db_data)); + + localbitcoinplusplus.encrypt + .messageBroadcasting(msg_sha256, data.trader_flo_address, + "supernode_to_supernode_backup_response"); + + // if (typeof su_db_data == "object") { + // su_db_data.trader_flo_address = data.trader_flo_address; + // let server_sync_response = RM_RPC + // .send_rpc + // .call(this, "supernode_to_supernode_backup_response", + // su_db_data); + // doSend(server_sync_response); + // } + }) + // } + // }) + break; + + case "supernode_to_supernode_backup_response": + console.log(res_obj.params[0]); + + if (typeof res_obj.params == "object" && typeof res_obj.params[0] == "object") { + let su_db_data = res_obj.params[0]; + + let db_data = localbitcoinplusplus.encrypt.decryptMessage(su_db_data.secret, su_db_data.senderPublicKeyString); + console.log(db_data); + return; + + if (typeof localbitcoinplusplus.wallets.my_local_flo_address !== "string" || + su_db_data.trader_flo_address !== localbitcoinplusplus.wallets.my_local_flo_address + ) return false; + + // const BACKUP_DB = new newBackupDB(); + // BACKUP_DB.createNewDB(); + + (async function () { + for (let tableStoreName in su_db_data) { + // skip loop if the property is from prototype + if (tableStoreName == 'trader_flo_address' || !su_db_data.hasOwnProperty( + tableStoreName)) continue; + + try { + let obj = su_db_data[tableStoreName]; + if (["crypto_balances", "cash_balances", "userPublicData"].includes( + tableStoreName)) { + if (obj.length > 0) { + for (var prop in obj) { + if (!obj.hasOwnProperty(prop)) continue; + await BACKUP_DB.backup_updateinDB(tableStoreName, obj[prop], obj[ + prop].trader_flo_address); + } + } + } else { + let resdbdata = await BACKUP_DB.backup_removeAllinDB(tableStoreName); + if (resdbdata !== false) { + if (obj.length > 0) { + for (var prop in obj) { + if (!obj.hasOwnProperty(prop)) continue; + await BACKUP_DB.backup_addDB(resdbdata, obj[prop]); + } + } + } + } + + } catch (error) { + console.log(error); + } + } + })(); + } + break; + case "messageBroadcasting": console.log(res_obj); try { @@ -15333,7 +17828,7 @@ function doSend(message) { - if(websocket.readyState!==1) { + if(websocket.readyState !== 1) { console.warn("Websocket not ready to broadcast messages."); //return; } @@ -15555,9 +18050,19 @@ temporary_ip: null } + const closestSupernodesTable = { + id: null, + ip: null, + is_live: null, + port: null, + timestamp: null, + trader_flo_address: null, + vectorClock: null + } + var db; const DBName = "localbitcoinDB"; - const request = window.indexedDB.open(DBName, 4); + const request = window.indexedDB.open(DBName, 5); request.onerror = function (event) { //https://stackoverflow.com/questions/13972385/invalidstateerror-while-opening-indexeddb-in-firefox @@ -15740,6 +18245,14 @@ unique: false }); } + if (!db.objectStoreNames.contains('closestSupernodesTable')) { + var objectStore = db.createObjectStore("closestSupernodesTable", { + keyPath: 'id' + }); + objectStore.createIndex('trader_flo_address', 'trader_flo_address', { + unique: false + }); + } } function readDB(tablename, id) { @@ -17069,25 +19582,53 @@ reactor.registerEvent('fireNodeGoodByeEvent'); reactor.addEventListener('fireNodeGoodByeEvent', function(evt_msg) { - console.log(evt_msg); let i = evt_msg.indexOf(' ') let temp_ip = evt_msg.substr(0, i) - console.log(temp_ip); - readDBbyIndex('ipTable', 'temporary_ip', temp_ip).then((op)=>{ - console.log(op); + readDBbyIndex('ipTable', 'temporary_ip', temp_ip).then(async op =>{ if(op.length < 1 || typeof op[0].temporary_ip !== 'string') return; let getFLOId = bitjs.FLO_TEST.pubkey2address(op[0].flo_public_key); if(localbitcoinplusplus.master_configurations.supernodesPubKeys .includes(op[0].flo_public_key)) { msg = `INFO: Supernode ${getFLOId} left.`; + reactor.dispatchEvent('getNeighborSupernodesItsVectorClockStatusForADeadSupernodeDB', getFLOId); } else { msg = `INFO: User node ${getFLOId} left.`; } showMessage(msg); }); - }) + }); + + reactor.registerEvent('getNeighborSupernodesItsVectorClockStatusForADeadSupernodeDB'); + reactor.addEventListener('getNeighborSupernodesItsVectorClockStatusForADeadSupernodeDB', async function(leaving_supernode_flo_id) { + let getNextClosestSuObj = await localbitcoinplusplus.kademlia.determineClosestSupernode(leaving_supernode_flo_id, 3); + let nextBackupSupernode = getNextClosestSuObj[0].data.id; + + if (typeof nextBackupSupernode !== "string") { + let msg = `WARNING: Failed to determine next closest backup supernode for ${leaving_supernode_flo_id}.`; + showMessage(msg); + throw new Error(msg); + } + + if (nextBackupSupernode == localbitcoinplusplus.wallets.my_local_flo_address) { + getNextClosestSuObj.map(nextSu=>{ + let nextSuConn = localbitcoinplusplus.backupWS.nextSu; + if(typeof nextSuConn !== "string") { + let msg = `WARNING: Failed to open a backup WS connection with Supernode ${nextSu}.`; + showMessage(msg); + throw new Error(msg); + } + let server_response = RM_RPC + .send_rpc + .call(this, "getNeighborSupernodesItsVectorClockStatusForADeadSupernodeDBReq", { + leaving_supernode_flo_id:leaving_supernode_flo_id + }); + server_response.globalParams.primarySupernode = nextBackupSupernode; + nextSuConn.ws_connection.send(server_response); + }); + } + });