public static void processPendingTransactions() { // TODO TODO improve to include failed transactions ulong last_block_height = IxianHandler.getLastBlockHeight(); lock (PendingTransactions.pendingTransactions) { long cur_time = Clock.getTimestamp(); List <PendingTransaction> tmp_pending_transactions = new List <PendingTransaction>(PendingTransactions.pendingTransactions); int idx = 0; foreach (var entry in tmp_pending_transactions) { Transaction t = entry.transaction; long tx_time = entry.addedTimestamp; if (t.applied != 0) { PendingTransactions.pendingTransactions.RemoveAll(x => x.transaction.id.SequenceEqual(t.id)); continue; } // if transaction expired, remove it from pending transactions if (last_block_height > ConsensusConfig.getRedactedWindowSize() && t.blockHeight < last_block_height - ConsensusConfig.getRedactedWindowSize()) { ActivityStorage.updateStatus(t.id, ActivityStatus.Error, 0); PendingTransactions.pendingTransactions.RemoveAll(x => x.transaction.id.SequenceEqual(t.id)); continue; } if (cur_time - tx_time > 40) // if the transaction is pending for over 40 seconds, resend { CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.transactionData, t.getBytes(), null); entry.addedTimestamp = cur_time; entry.confirmedNodeList.Clear(); } if (entry.confirmedNodeList.Count() >= 3) // if we get transaction from 3 nodes, we can consider it as confirmed { if (entry.messageId != null) { StreamProcessor.confirmMessage(entry.messageId); } continue; } if (cur_time - tx_time > 20) // if the transaction is pending for over 20 seconds, send inquiry { CoreProtocolMessage.broadcastGetTransaction(t.id, 0, null, false); } idx++; } } }
public static void processPendingTransactions() { // TODO TODO improve to include failed transactions ulong last_block_height = IxianHandler.getLastBlockHeight(); lock (PendingTransactions.pendingTransactions) { long cur_time = Clock.getTimestamp(); List <PendingTransaction> tmp_pending_transactions = new List <PendingTransaction>(PendingTransactions.pendingTransactions); int idx = 0; foreach (var entry in tmp_pending_transactions) { Transaction t = entry.transaction; long tx_time = entry.addedTimestamp; if (t.applied != 0) { PendingTransactions.pendingTransactions.RemoveAll(x => x.transaction.id.SequenceEqual(t.id)); continue; } // if transaction expired, remove it from pending transactions if (last_block_height > ConsensusConfig.getRedactedWindowSize() && t.blockHeight < last_block_height - ConsensusConfig.getRedactedWindowSize()) { Console.WriteLine("Error sending the transaction {0}", Transaction.txIdV8ToLegacy(t.id)); PendingTransactions.pendingTransactions.RemoveAll(x => x.transaction.id.SequenceEqual(t.id)); continue; } if (cur_time - tx_time > 40) // if the transaction is pending for over 40 seconds, resend { CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.transactionData, t.getBytes(), null); entry.addedTimestamp = cur_time; entry.confirmedNodeList.Clear(); } if (entry.confirmedNodeList.Count() > 3) // already received 3+ feedback { continue; } if (cur_time - tx_time > 20) // if the transaction is pending for over 20 seconds, send inquiry { CoreProtocolMessage.broadcastGetTransaction(Transaction.txIdV8ToLegacy(t.id), 0); } idx++; } } }
override protected bool sendInventoryRequest(InventoryItem item, RemoteEndpoint endpoint) { switch (item.type) { case InventoryItemTypes.block: return(handleBlock(item, endpoint)); case InventoryItemTypes.blockSignature: return(handleSignature(item, endpoint)); case InventoryItemTypes.keepAlive: return(handleKeepAlive(item, endpoint)); case InventoryItemTypes.transaction: CoreProtocolMessage.broadcastGetTransaction(item.hash, 0, endpoint); return(true); } return(false); }
public void insertMessage(FriendMessage message) { if (friend.approved == false) { if (message.type == FriendMessageType.requestAdd) { // Call webview methods on the main UI thread only Utils.sendUiCommand(webView, "showContactRequest", "1"); message.read = true; return; } } else { // Don't show if the friend is already approved if (message.type == FriendMessageType.requestAdd) { return; } } string prefix = "addMe"; string avatar = ""; string address = ""; string nick = ""; if (!message.localSender) { if (friend.bot) { if (message.senderAddress != null) { address = Base58Check.Base58CheckEncoding.EncodePlain(message.senderAddress); } nick = message.senderNick; if (nick == "") { if (message.senderAddress != null && friend.contacts.ContainsKey(message.senderAddress)) { nick = friend.contacts[message.senderAddress].nick; } } if (nick == "") { nick = address; } } prefix = "addThem"; if (message.senderAddress != null) { avatar = Node.localStorage.getAvatarPath(Base58Check.Base58CheckEncoding.EncodePlain(message.senderAddress)); } else { avatar = Node.localStorage.getAvatarPath(Base58Check.Base58CheckEncoding.EncodePlain(friend.walletAddress)); } if (avatar == null) { avatar = "img/spixiavatar.png"; } } if (message.type == FriendMessageType.requestFunds) { string status = "WAITING CONFIRMATION"; string status_icon = "fa-clock"; string amount = message.message; string txid = ""; bool enableView = false; if (!message.localSender) { enableView = true; } if (message.message.StartsWith("::")) { status = "DECLINED"; status_icon = "fa-exclamation-circle"; amount = message.message.Substring(2); txid = Crypto.hashToString(message.id); enableView = false; } else if (message.message.StartsWith(":")) { status = "PENDING"; txid = message.message.Substring(1); bool confirmed = true; Transaction transaction = TransactionCache.getTransaction(txid); if (transaction == null) { transaction = TransactionCache.getUnconfirmedTransaction(txid); confirmed = false; } amount = "?"; if (transaction != null) { amount = transaction.amount.ToString(); if (confirmed) { status = "CONFIRMED"; status_icon = "fa-check-circle"; } } else { // TODO think about how to make this more private CoreProtocolMessage.broadcastGetTransaction(txid, 0, null); } enableView = true; } if (message.localSender) { Utils.sendUiCommand(webView, "addPaymentRequest", Crypto.hashToString(message.id), txid, address, nick, avatar, "Payment request SENT", amount, status, status_icon, message.timestamp.ToString(), message.localSender.ToString(), message.confirmed.ToString(), message.read.ToString(), enableView.ToString()); } else { Utils.sendUiCommand(webView, "addPaymentRequest", Crypto.hashToString(message.id), txid, address, nick, avatar, "Payment request RECEIVED", amount, status, status_icon, message.timestamp.ToString(), "", message.confirmed.ToString(), message.read.ToString(), enableView.ToString()); } } if (message.type == FriendMessageType.sentFunds) { bool confirmed = true; Transaction transaction = TransactionCache.getTransaction(message.message); if (transaction == null) { transaction = TransactionCache.getUnconfirmedTransaction(message.message); confirmed = false; } string status = "PENDING"; string status_icon = "fa-clock"; string amount = "?"; if (transaction != null) { if (confirmed) { status = "CONFIRMED"; status_icon = "fa-check-circle"; } if (message.localSender) { amount = transaction.amount.ToString(); } else { amount = HomePage.calculateReceivedAmount(transaction).ToString(); } } else { // TODO think about how to make this more private CoreProtocolMessage.broadcastGetTransaction(message.message, 0, null); } // Call webview methods on the main UI thread only if (message.localSender) { Utils.sendUiCommand(webView, "addPaymentRequest", Crypto.hashToString(message.id), message.message, address, nick, avatar, "Payment SENT", amount, status, status_icon, message.timestamp.ToString(), message.localSender.ToString(), message.confirmed.ToString(), message.read.ToString(), "True"); } else { Utils.sendUiCommand(webView, "addPaymentRequest", Crypto.hashToString(message.id), message.message, address, nick, avatar, "Payment RECEIVED", amount, status, status_icon, message.timestamp.ToString(), "", message.confirmed.ToString(), message.read.ToString(), "True"); } } if (message.type == FriendMessageType.fileHeader) { string[] split = message.message.Split(new string[] { ":" }, StringSplitOptions.None); if (split != null && split.Length > 1) { string uid = split[0]; string name = split[1]; string progress = "0"; if (message.completed) { progress = "100"; } Utils.sendUiCommand(webView, "addFile", Crypto.hashToString(message.id), address, nick, avatar, uid, name, message.timestamp.ToString(), message.localSender.ToString(), message.confirmed.ToString(), message.read.ToString(), progress, message.completed.ToString()); } } if (message.type == FriendMessageType.standard) { // Normal chat message // Call webview methods on the main UI thread only Utils.sendUiCommand(webView, prefix, Crypto.hashToString(message.id), address, nick, avatar, message.message, message.timestamp.ToString(), message.confirmed.ToString(), message.read.ToString()); } updateMessageReadStatus(message); }
private void rollForward() { bool sleep = false; ulong lowestBlockNum = getLowestBlockNum(); ulong syncToBlock = syncTargetBlockNum; if (Node.blockChain.Count > 5) { lock (pendingBlocks) { pendingBlocks.RemoveAll(x => x.blockNum < Node.blockChain.getLastBlockNum() - 5); } } lock (pendingBlocks) { // Loop until we have no more pending blocks do { handleWatchDog(); ulong next_to_apply = lowestBlockNum; if (Node.blockChain.Count > 0) { next_to_apply = Node.blockChain.getLastBlockNum() + 1; } if (next_to_apply > syncToBlock) { // we have everything, clear pending blocks and break pendingBlocks.Clear(); lock (requestedBlockTimes) { requestedBlockTimes.Clear(); } break; } Block b = pendingBlocks.Find(x => x.blockNum == next_to_apply); if (b == null) { lock (requestedBlockTimes) { if (requestBlockAgain(next_to_apply)) { // the node isn't connected yet, wait a while sleep = true; } } break; } b = new Block(b); if (b.version > Block.maxVersion) { Logging.error("Received block {0} with a version higher than this node can handle, discarding the block.", b.blockNum); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); Node.blockProcessor.networkUpgraded = true; sleep = true; break; } else { Node.blockProcessor.networkUpgraded = false; } if (next_to_apply > 5) { ulong targetBlock = next_to_apply - 5; Block tb = pendingBlocks.Find(x => x.blockNum == targetBlock); if (tb != null) { if (tb.blockChecksum.SequenceEqual(Node.blockChain.getBlock(tb.blockNum).blockChecksum) && Node.blockProcessor.verifyBlockBasic(tb) == BlockVerifyStatus.Valid) { if (Node.blockProcessor.verifyBlockSignatures(tb)) { Node.blockChain.refreshSignatures(tb, true); } else { Logging.warn("Target block " + tb.blockNum + " does not have the required consensus."); } } pendingBlocks.RemoveAll(x => x.blockNum == tb.blockNum); } } try { Logging.info(String.Format("Sync: Applying block #{0}/{1}.", b.blockNum, syncToBlock)); bool ignoreWalletState = true; if (b.blockNum > wsSyncConfirmedBlockNum || Config.fullStorageDataVerification) { ignoreWalletState = false; } b.powField = null; // wallet state is correct as of wsConfirmedBlockNumber, so before that we call // verify with a parameter to ignore WS tests, but do all the others BlockVerifyStatus b_status = BlockVerifyStatus.Valid; if (b.fromLocalStorage) { bool missing = false; foreach (string txid in b.transactions) { if (!running) { break; } Transaction t = TransactionPool.getTransaction(txid, b.blockNum, true); if (t != null) { t.applied = 0; if (!TransactionPool.addTransaction(t, true, null, Config.fullStorageDataVerification)) { Logging.error("Error adding a transaction {0} from storage", txid); } } else { CoreProtocolMessage.broadcastGetTransaction(txid, b.blockNum); missing = true; } } if (missing) { sleep = true; break; } } if (b.blockNum > wsSyncConfirmedBlockNum || b.fromLocalStorage == false || Config.fullStorageDataVerification) { b_status = Node.blockProcessor.verifyBlock(b, ignoreWalletState); } else { b_status = Node.blockProcessor.verifyBlockBasic(b, false); } if (b_status == BlockVerifyStatus.Indeterminate) { Logging.info(String.Format("Waiting for missing transactions from block #{0}...", b.blockNum)); Thread.Sleep(100); return; } if (b_status != BlockVerifyStatus.Valid) { Logging.warn(String.Format("Block #{0} {1} is invalid. Discarding and requesting a new one.", b.blockNum, Crypto.hashToString(b.blockChecksum))); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); return; } if (!b.fromLocalStorage && !Node.blockProcessor.verifyBlockSignatures(b) && Node.blockChain.Count > 16) { Logging.warn(String.Format("Block #{0} {1} doesn't have the required consensus. Discarding and requesting a new one.", b.blockNum, Crypto.hashToString(b.blockChecksum))); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); return; } bool sigFreezeCheck = Node.blockProcessor.verifySignatureFreezeChecksum(b, null); // Apply transactions when rolling forward from a recover file without a synced WS if (b.blockNum > wsSyncConfirmedBlockNum) { if (Node.blockChain.Count <= 5 || sigFreezeCheck) { Node.blockProcessor.applyAcceptedBlock(b); if (b.version >= BlockVer.v5 && b.lastSuperBlockChecksum == null) { // skip WS checksum check } else { if (b.lastSuperBlockChecksum != null || b.blockNum % Config.saveWalletStateEveryBlock == 0) { byte[] wsChecksum = Node.walletState.calculateWalletStateChecksum(); if (wsChecksum == null || !wsChecksum.SequenceEqual(b.walletStateChecksum)) { Logging.error(String.Format("After applying block #{0}, walletStateChecksum is incorrect!. Block's WS: {1}, actual WS: {2}", b.blockNum, Crypto.hashToString(b.walletStateChecksum), Crypto.hashToString(wsChecksum))); handleWatchDog(true); return; } } } if (b.blockNum % Config.saveWalletStateEveryBlock == 0) { DLT.Meta.WalletStateStorage.saveWalletState(b.blockNum); } } } else { if (syncToBlock == b.blockNum) { if (b.version >= BlockVer.v5 && b.lastSuperBlockChecksum == null) { // skip WS checksum check } else { byte[] wsChecksum = Node.walletState.calculateWalletStateChecksum(); if (wsChecksum == null || !wsChecksum.SequenceEqual(b.walletStateChecksum)) { Logging.warn(String.Format("Block #{0} is last and has an invalid WSChecksum. Discarding and requesting a new one.", b.blockNum)); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); handleWatchDog(true); return; } } } } if (Node.blockChain.Count <= 5 || sigFreezeCheck) { //Logging.info(String.Format("Appending block #{0} to blockChain.", b.blockNum)); if (b.blockNum <= wsSyncConfirmedBlockNum) { if (!TransactionPool.setAppliedFlagToTransactionsFromBlock(b)) { pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); return; } } if (b.blockNum > 12 && b.blockNum + 5 >= IxianHandler.getHighestKnownNetworkBlockHeight()) { if (Node.isMasterNode()) { byte[][] signature_data = b.applySignature(); // applySignature() will return signature_data, if signature was applied and null, if signature was already present from before if (signature_data != null) { // ProtocolMessage.broadcastNewBlock(localNewBlock); ProtocolMessage.broadcastNewBlockSignature(b.blockNum, b.blockChecksum, signature_data[0], signature_data[1]); } } } Node.blockChain.appendBlock(b, !b.fromLocalStorage); resetWatchDog(b.blockNum); } else if (Node.blockChain.Count > 5 && !sigFreezeCheck) { // invalid sigfreeze, waiting for the correct block pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); return; } } catch (Exception e) { Logging.error(String.Format("Exception occured while syncing block #{0}: {1}", b.blockNum, e)); } pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); } while (pendingBlocks.Count > 0 && running); } if (!sleep && Node.blockChain.getLastBlockNum() >= syncToBlock) { if (verifyLastBlock()) { resetWatchDog(0); sleep = false; } else { handleWatchDog(true); sleep = true; } } if (sleep) { Thread.Sleep(500); } }
public static void onBotAction(byte[] action_data, RemoteEndpoint endpoint, int channel = 0) { SpixiBotAction sba = new SpixiBotAction(action_data); switch (sba.action) { case SpixiBotActionCode.getChannels: sendChannels(endpoint); break; case SpixiBotActionCode.getInfo: Node.users.setPubKey(endpoint.presence.wallet, endpoint.serverPubKey, false); sendInfo(endpoint.presence.wallet); break; case SpixiBotActionCode.getUsers: sendUsers(endpoint); break; case SpixiBotActionCode.getUser: sendUser(endpoint.presence.wallet, Node.users.getUser(sba.data)); break; case SpixiBotActionCode.payment: StreamTransaction stream_tx = new StreamTransaction(sba.data); if (!stream_tx.transaction.toList.Keys.First().SequenceEqual(IxianHandler.getWalletStorage().getPrimaryAddress())) { Logging.warn("Received transaction txid " + stream_tx.transaction.id + " from " + Base58Check.Base58CheckEncoding.EncodePlain(endpoint.presence.wallet) + " that's not for this node."); return; } StreamMessage sm = pendingMessages.Find(x => x.id.SequenceEqual(stream_tx.messageID)); if (sm == null) { // TODO TODO TODO send get message request to the client Logging.warn("Received transaction txid " + stream_tx.transaction.id + " from " + Base58Check.Base58CheckEncoding.EncodePlain(endpoint.presence.wallet) + " but have no message for this transaction."); return; } IxiNumber price = getMessagePrice(sm.sender, sm.data.Length); if (stream_tx.transaction.amount < price) { Logging.warn("Received transaction txid " + stream_tx.transaction.id + " from " + Base58Check.Base58CheckEncoding.EncodePlain(endpoint.presence.wallet) + " that has lower than expected amount."); return; } CoreProtocolMessage.broadcastProtocolMessage(new char[] { 'M', 'H' }, ProtocolMessageCode.transactionData, stream_tx.transaction.getBytes(), null); CoreProtocolMessage.broadcastGetTransaction(stream_tx.transaction.id, 0, null, false); PendingTransactions.addPendingLocalTransaction(stream_tx.transaction, stream_tx.messageID); break; case SpixiBotActionCode.enableNotifications: bool send_notifications = false; if (sba.data[0] == 1) { send_notifications = true; } Node.users.getUser(endpoint.presence.wallet).sendNotification = send_notifications; Node.users.writeContactsToFile(); break; } }
private void rollForward() { bool sleep = false; ulong lowestBlockNum = getLowestBlockNum(); ulong syncToBlock = syncTargetBlockNum; if (Node.blockChain.Count > 5) { lock (pendingBlocks) { pendingBlocks.RemoveAll(x => x.blockNum < Node.blockChain.getLastBlockNum() - 5); } } lock (pendingBlocks) { // Loop until we have no more pending blocks do { ulong next_to_apply = lowestBlockNum; if (Node.blockChain.Count > 0) { next_to_apply = Node.blockChain.getLastBlockNum() + 1; } if (next_to_apply > syncToBlock) { // we have everything, clear pending blocks and break pendingBlocks.Clear(); lock (requestedBlockTimes) { requestedBlockTimes.Clear(); } break; } Block b = pendingBlocks.Find(x => x.blockNum == next_to_apply); if (b == null) { lock (requestedBlockTimes) { if (requestBlockAgain(next_to_apply)) { // the node isn't connected yet, wait a while sleep = true; } } break; } b = new Block(b); if (Node.blockChain.Count == 0 && b.blockNum > 1) { Block tmp_b = Node.blockChain.getBlock(b.blockNum - 1, true, true); if (tmp_b != null) { Node.blockChain.setLastBlockVersion(tmp_b.version); } else { Node.blockChain.setLastBlockVersion(b.version); } } if (b.version > Block.maxVersion) { Logging.error("Received block {0} with a version higher than this node can handle, discarding the block.", b.blockNum); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); Node.blockProcessor.networkUpgraded = true; sleep = true; break; } else { Node.blockProcessor.networkUpgraded = false; } if (next_to_apply > 5) { ulong targetBlock = next_to_apply - 5; Block tb = pendingBlocks.Find(x => x.blockNum == targetBlock); if (tb != null) { Block local_block = Node.blockChain.getBlock(tb.blockNum); if (local_block != null && tb.blockChecksum.SequenceEqual(local_block.blockChecksum) && Node.blockProcessor.verifyBlockBasic(tb) == BlockVerifyStatus.Valid) { if (Node.blockProcessor.verifyBlockSignatures(tb, null)) { Node.blockChain.refreshSignatures(tb, true); } else { Logging.warn("Target block " + tb.blockNum + " does not have the required consensus."); } } pendingBlocks.RemoveAll(x => x.blockNum == tb.blockNum); } } try { Logging.info("Sync: Applying block #{0}/{1}.", b.blockNum, syncToBlock); bool ignoreWalletState = true; if (b.blockNum > wsSyncConfirmedBlockNum || Config.fullStorageDataVerification) { ignoreWalletState = false; } b.powField = null; // wallet state is correct as of wsConfirmedBlockNumber, so before that we call // verify with a parameter to ignore WS tests, but do all the others BlockVerifyStatus b_status = BlockVerifyStatus.Valid; if (b.fromLocalStorage) { // TODO TODO improve this section with NodeStorage.getTransactionsInBlock once rocksdb switch happens bool missing = false; foreach (byte[] txid in b.transactions) { if (!running) { break; } Transaction t = TransactionPool.getUnappliedTransaction(txid); if (t == null) { t = Node.storage.getTransaction(txid, b.blockNum); if (t != null) { t.applied = 0; TransactionPool.addTransaction(t, true, null, Config.fullStorageDataVerification); } else { CoreProtocolMessage.broadcastGetTransaction(txid, b.blockNum); missing = true; } } } if (missing) { Logging.info("Requesting missing transactions for block {0}", b.blockNum); Thread.Sleep(100); break; } } if (b.blockNum > wsSyncConfirmedBlockNum || b.fromLocalStorage == false || Config.fullStorageDataVerification) { b_status = Node.blockProcessor.verifyBlock(b, ignoreWalletState); } else { b_status = Node.blockProcessor.verifyBlockBasic(b, false); } if (b_status == BlockVerifyStatus.Indeterminate) { if (lastProcessedBlockNum < b.blockNum) { lastProcessedBlockNum = b.blockNum; lastProcessedBlockTime = Clock.getTimestamp(); } if (Clock.getTimestamp() - lastProcessedBlockTime > ConsensusConfig.blockGenerationInterval * 2) { Logging.info("Sync: Discarding indeterminate block #{0}, due to timeout...", b.blockNum); Node.blockProcessor.blacklistBlock(b); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); } else { Logging.info("Sync: Waiting for missing transactions from block #{0}...", b.blockNum); } Thread.Sleep(100); return; } if (b_status != BlockVerifyStatus.Valid) { Logging.warn("Block #{0} {1} is invalid. Discarding and requesting a new one.", b.blockNum, Crypto.hashToString(b.blockChecksum)); Node.blockProcessor.blacklistBlock(b); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); if (b_status == BlockVerifyStatus.PotentiallyForkedBlock && b.blockNum + 7 > lastBlockToReadFromStorage) { Node.blockProcessor.handleForkedFlag(); } return; } if (!b.fromLocalStorage && !Node.blockProcessor.verifyBlockSignatures(b, null) && Node.blockChain.Count > 16) { Logging.warn("Block #{0} {1} doesn't have the required consensus. Discarding and requesting a new one.", b.blockNum, Crypto.hashToString(b.blockChecksum)); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); return; } bool sigFreezeCheck = Node.blockProcessor.verifySignatureFreezeChecksum(b, null); // Apply transactions when rolling forward from a recover file without a synced WS if (b.blockNum > wsSyncConfirmedBlockNum) { if (Node.blockChain.Count <= 5 || sigFreezeCheck) { Node.walletState.beginTransaction(b.blockNum, false); bool applied = false; try { applied = Node.blockProcessor.applyAcceptedBlock(b); if (applied) { Node.walletState.commitTransaction(b.blockNum); } }catch (Exception e) { Logging.error("Error occured during block sync, while applying/commiting transactions: " + e); } if (!applied) { Logging.warn("Error applying Block #{0} {1}. Reverting, discarding and requesting a new one.", b.blockNum, Crypto.hashToString(b.blockChecksum)); Node.walletState.revertTransaction(b.blockNum); Node.blockChain.revertBlockTransactions(b); Node.blockProcessor.blacklistBlock(b); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); return; } else { if (b.version >= BlockVer.v5 && b.lastSuperBlockChecksum == null) { // skip WS checksum check } else { if (b.lastSuperBlockChecksum != null) { byte[] wsChecksum = Node.walletState.calculateWalletStateChecksum(); if (wsChecksum == null || !wsChecksum.SequenceEqual(b.walletStateChecksum)) { Logging.error("After applying block #{0}, walletStateChecksum is incorrect!. Block's WS: {1}, actual WS: {2}", b.blockNum, Crypto.hashToString(b.walletStateChecksum), Crypto.hashToString(wsChecksum)); Node.walletState.revertTransaction(b.blockNum); Node.blockChain.revertBlockTransactions(b); Node.blockProcessor.blacklistBlock(b); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); return; } } } if (b.blockNum % Config.saveWalletStateEveryBlock == 0) { DLT.Meta.WalletStateStorage.saveWalletState(b.blockNum); } } } } else { if (syncToBlock == b.blockNum) { if (b.version >= BlockVer.v5 && b.lastSuperBlockChecksum == null) { // skip WS checksum check } else { byte[] wsChecksum = Node.walletState.calculateWalletStateChecksum(); if (wsChecksum == null || !wsChecksum.SequenceEqual(b.walletStateChecksum)) { Logging.warn("Block #{0} is last and has an invalid WSChecksum. Discarding and requesting a new one.", b.blockNum); Node.blockProcessor.blacklistBlock(b); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); return; } } } } if (Node.blockChain.Count <= 5 || sigFreezeCheck) { //Logging.info(String.Format("Appending block #{0} to blockChain.", b.blockNum)); if (b.blockNum <= wsSyncConfirmedBlockNum) { if (!TransactionPool.setAppliedFlagToTransactionsFromBlock(b)) { Node.blockChain.revertBlockTransactions(b); Node.blockProcessor.blacklistBlock(b); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); return; } } if (b.blockNum > 12 && b.blockNum + 5 >= IxianHandler.getHighestKnownNetworkBlockHeight()) { if (Node.isMasterNode() && b.blockNum > 7) { byte[][] signature_data = b.applySignature(); // applySignature() will return signature_data, if signature was applied and null, if signature was already present from before if (signature_data != null) { Node.inventoryCache.setProcessedFlag(InventoryItemTypes.blockSignature, InventoryItemSignature.getHash(signature_data[1], b.blockChecksum), true); // ProtocolMessage.broadcastNewBlock(localNewBlock); SignatureProtocolMessages.broadcastBlockSignature(signature_data[0], signature_data[1], b.blockNum, b.blockChecksum, null, null); } } } Node.blockChain.appendBlock(b, !b.fromLocalStorage); } else if (Node.blockChain.Count > 5 && !sigFreezeCheck) { if (CoreConfig.preventNetworkOperations || Config.recoverFromFile) { var last_block = lastBlocks.Find(x => x.blockNum == b.blockNum - 5); if (last_block != null) { pendingBlocks.Add(last_block); } return; } // invalid sigfreeze, waiting for the correct block Logging.warn("Block #{0} {1} doesn't have the correct sigfreezed block. Discarding and requesting a new one.", b.blockNum, Crypto.hashToString(b.blockChecksum)); pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); requestBlockAgain(b.blockNum); return; } } catch (Exception e) { Logging.error("Exception occured while syncing block #{0}: {1}", b.blockNum, e); } if (Config.enableChainReorgTest) { if (!Node.blockProcessor.chainReorgTest(b.blockNum)) { pendingBlocks.RemoveAll(x => x.blockNum + 6 < b.blockNum); } } else { pendingBlocks.RemoveAll(x => x.blockNum == b.blockNum); } Node.blockProcessor.cleanupBlockBlacklist(); } while (pendingBlocks.Count > 0 && running); } if (!sleep && Node.blockChain.getLastBlockNum() >= syncToBlock) { if (verifyLastBlock()) { sleep = false; } else { sleep = true; } } if (sleep) { Thread.Sleep(500); } }