/// <summary> /// Aggiunge i blocchi presenti nel vettore e ritorna l'indice dell'ultimo blocco aggiunto. /// </summary> /// <param name="Blocks"></param> /// <returns></returns> public ulong Add(CTemporaryBlock[] Blocks) { ulong counter = 0; string filepath = PATH + "\\" + FILENAME; //(!) e se scarico tutta la blockchain e da un certo punto in poi sbagliata? foreach (CTemporaryBlock b in Blocks) { if (b == null) { break; } if (CValidator.ValidateBlock(b, true)) { if (b.Header.BlockNumber == LastValidBlock.Header.BlockNumber) { break; } mLastValidBlock = b as CBlock; counter++; lock (Instance) { MemPool.Instance.RemoveBlock(b); UTXOManager.Instance.ApplyBlock(b); File.AppendAllText(filepath, (b as CBlock).Serialize() + '\n'); } } else { break; } } return(counter); }
private CBlock FindLastCommonBlocks() { ulong minLength = ulong.MaxValue, tmp = 0; int rqsID = 0; bool found = false; Stack <CHeader> headers = new Stack <CHeader>(); CBlock res = null; foreach (CPeer p in Peers) { try { rqsID = p.SendRequest(new CMessage(EMessageType.Request, ERequestType.ChainLength)); tmp = p.ReceiveULong(rqsID, 5000); if (tmp < minLength) { minLength = tmp; } } catch (SocketException) { } p.Socket.ReceiveTimeout = 0; } CRange r = new CRange(CBlockChain.Instance.LastValidBlock.Header.BlockNumber, minLength); if (r.End != ulong.MaxValue && r.Start < r.End) { //trova l'ultimo blocco uguale tra i peer e salva l'indice di quel blocco in r.start int ID = 0; while (r.Start < r.End) { found = true; tmp = (r.Start + r.End) / 2; if (r.End - r.Start == 1) { tmp++; } foreach (CPeer p in Peers) { ID = p.SendRequest(new CMessage(EMessageType.Request, ERequestType.GetHeader, EDataType.ULong, Convert.ToString(tmp))); headers.Push(p.ReceiveHeader(ID, 5000)); } while (headers.Count > 1 && found) { if (!(headers?.Pop().Hash == headers?.Peek().Hash)) { found = false; } } if (headers.Count == 1) { headers.Pop(); } //se tutti i blocchi sono uguali allora found=true, mentre se ce n'è qualcuno di diverso found=false if (found) { r.Start = tmp; } else if (!(r.End - r.Start == 1)) { r.End = tmp; } else { r.End--; } } //controlla se l'ultimo blocco è valido? foreach (CPeer p in Peers) { ID = p.SendRequest(new CMessage(EMessageType.Request, ERequestType.DownloadBlock, EDataType.ULong, Convert.ToString(r.Start))); res = p.ReceiveBlock(ID, 5000); if (res != null && CValidator.ValidateBlock(res)) { break; } else { p.Disconnect(); } p.Socket.ReceiveTimeout = 0; } return(res); } else { return(CBlockChain.Instance.LastValidBlock); } }
private void UpdateBlockchain() { bool isSynced = false; ulong addedBlocks = 0; CTemporaryBlock[] DownloadedBlock; CTemporaryBlock[] newBlocks; CHeaderChain[] forkChains; CHeaderChain bestChain; CBlock lastCommonBlock; CTemporaryBlock otherLastValidBlock; lastCommonBlock = mPeers.DoRequest(ERequest.LastCommonValidBlock) as CBlock; //trova l'utlimo blocco comune tra i peers otherLastValidBlock = mPeers.DoRequest(ERequest.LastValidBlock) as CTemporaryBlock; //trova l'ultimo blocco valido tra i peer if (Program.DEBUG) { if (otherLastValidBlock != null) { CIO.DebugOut("Il numero di blocco di otherLastValidBlock è " + otherLastValidBlock.Header.BlockNumber + "."); } else { CIO.DebugOut("Nessun otherLastValidBlock ricevuto."); } } if (CBlockChain.Instance.LastValidBlock.Header.BlockNumber < otherLastValidBlock?.Header.BlockNumber) { isSynced = false; } else if (otherLastValidBlock != null && CBlockChain.Instance.RetriveBlock(otherLastValidBlock.Header.BlockNumber).Header.Hash == otherLastValidBlock.Header.Hash) { isSynced = true; } else if (otherLastValidBlock != null) { isSynced = true; otherLastValidBlock.Sender.Disconnect(); } else { isSynced = true; } //TODO potrebbero dover essere scaricati un numero maggiore di MAXINT blocchi while (!isSynced) { newBlocks = mPeers.DoRequest(ERequest.DownloadMissingBlock, new object[] { CBlockChain.Instance.LastValidBlock.Header.BlockNumber + 1, lastCommonBlock.Header.BlockNumber + 1 }) as CTemporaryBlock[]; /*foreach (CTemporaryBlock block in newBlocks) * { * UTXOManager.Instance.ApplyBlock(block); * }*/ CBlockChain.Instance.Add(newBlocks); forkChains = mPeers.DoRequest(ERequest.FindParallelChain, lastCommonBlock) as CHeaderChain[]; if (forkChains.Length > 0) { foreach (CHeaderChain hc in forkChains) { hc.DownloadHeaders(); } bestChain = CBlockChain.Instance.BestChain(forkChains); if (CValidator.ValidateHeaderChain(bestChain)) { DownloadedBlock = CPeers.Instance.DistribuiteDownloadBlocks(bestChain.InitialIndex + 1, bestChain.FinalIndex); /*foreach(CTemporaryBlock block in DownloadedBlock) * { * UTXOManager.Instance.ApplyBlock(block); * }*/ mPeers.ValidPeers(bestChain.Peers); addedBlocks = CBlockChain.Instance.Add(DownloadedBlock); if (addedBlocks >= bestChain.Length) //solo se scarica tutti i blocchi { isSynced = true; } } else { mPeers.InvalidPeers(bestChain.Peers); otherLastValidBlock = mPeers.DoRequest(ERequest.LastValidBlock) as CTemporaryBlock; lastCommonBlock = mPeers.DoRequest(ERequest.LastCommonValidBlock) as CTemporaryBlock; } } } if (Program.DEBUG) { CIO.DebugOut("Sincronizzazione Blockchain terminata!"); } mPeers.CanReceiveBlock = true; }
private void ExecuteRequest() { CMessage rqs; while (mIsConnected) { Thread.Sleep(100); if (RequestQueue.Count > 0) { rqs = RequestQueue.Dequeue(); switch (rqs.RqsType) { case ERequestType.UpdPeers: { if (Program.DEBUG) { CIO.DebugOut("UpdPeers received by " + mIp); } //(!) è meglio farsi ritornare la lista e poi usare json? SendRequest(new CMessage(EMessageType.Data, ERequestType.NULL, EDataType.PeersList, CPeers.Instance.PeersList(), rqs.ID)); break; } case ERequestType.NewBlockMined: { if (CPeers.Instance.CanReceiveBlock) { if (Program.DEBUG) { CIO.DebugOut("NewBlockMined received by " + mIp); } CTemporaryBlock newBlock = new CTemporaryBlock(CBlock.Deserialize(rqs.Data), this); if (!CValidator.ValidateBlock(newBlock) && newBlock.Header.BlockNumber < CBlockChain.Instance.LastValidBlock.Header.BlockNumber) { Disconnect(); break; } //TODO scaricare i blocchi mancanti se ne mancano(sono al blocco 10 e mi arriva il blocco 50) if (!CBlockChain.Instance.AddNewMinedBlock(newBlock)) { Stack <CTemporaryBlock> blocks = new Stack <CTemporaryBlock>(); int ID = 0; blocks.Push(newBlock); for (ulong i = newBlock.Header.BlockNumber - 1; i > CBlockChain.Instance.LastValidBlock.Header.BlockNumber; i--) { ID = SendRequest(new CMessage(EMessageType.Request, ERequestType.DownloadBlock, EDataType.ULong, Convert.ToString(i))); blocks.Push(new CTemporaryBlock(JsonConvert.DeserializeObject <CBlock>(ReceiveData(ID, 5000).Data), this)); if (!CValidator.ValidateBlock(blocks.Peek()) && blocks.Peek().Header.BlockNumber < CBlockChain.Instance.LastValidBlock.Header.BlockNumber) { Disconnect(); break; } if (CBlockChain.Instance.AddNewMinedBlock(blocks.Peek())) { blocks.Pop(); for (int j = blocks.Count; j > 0; j--) { CBlockChain.Instance.AddNewMinedBlock(blocks.Pop()); } } } } } break; } case ERequestType.GetLastHeader: { if (Program.DEBUG) { CIO.DebugOut("GetLastHeader received by " + mIp); } SendRequest(new CMessage(EMessageType.Data, ERequestType.NULL, EDataType.Header, JsonConvert.SerializeObject(CBlockChain.Instance.LastValidBlock.Header), rqs.ID)); break; } case ERequestType.ChainLength: { if (Program.DEBUG) { CIO.DebugOut("ChainLength received by " + mIp); } SendRequest(new CMessage(EMessageType.Data, ERequestType.NULL, EDataType.ULong, Convert.ToString(CBlockChain.Instance.LastValidBlock.Header.BlockNumber), rqs.ID)); break; } case ERequestType.GetLastValid: { if (Program.DEBUG) { CIO.DebugOut("GetLastValid received by " + mIp); } SendRequest(new CMessage(EMessageType.Data, ERequestType.NULL, EDataType.Block, CBlockChain.Instance.LastValidBlock.Serialize(), rqs.ID)); break; } case ERequestType.DownloadBlock: { if (Program.DEBUG) { CIO.DebugOut("DownloadBlock received by " + mIp); } SendRequest(new CMessage(EMessageType.Data, ERequestType.NULL, EDataType.Block, JsonConvert.SerializeObject(CBlockChain.Instance.RetriveBlock(Convert.ToUInt64(rqs.Data), true)), rqs.ID)); break; } case ERequestType.DownloadBlocks: { if (Program.DEBUG) { CIO.DebugOut("DownloadBlocks received by " + mIp); } SendRequest(new CMessage(EMessageType.Data, ERequestType.NULL, EDataType.BlockList, JsonConvert.SerializeObject(CBlockChain.Instance.RetriveBlocks(Convert.ToUInt64(rqs.Data.Split(';')[0]), Convert.ToUInt64(rqs.Data.Split(';')[1]))), rqs.ID)); break; } case ERequestType.DownloadHeaders: { if (Program.DEBUG) { CIO.DebugOut("DownloadBlocks received by " + mIp); } SendRequest(new CMessage(EMessageType.Data, ERequestType.NULL, EDataType.HeaderList, JsonConvert.SerializeObject(CBlockChain.Instance.RetriveHeaders(Convert.ToUInt64(rqs.Data.Split(';')[0]), Convert.ToUInt64(rqs.Data.Split(';')[1]))), rqs.ID)); break; } case ERequestType.GetHeader: { if (Program.DEBUG) { CIO.DebugOut("GetLastHeader received by " + mIp); } SendRequest(new CMessage(EMessageType.Data, ERequestType.NULL, EDataType.Header, JsonConvert.SerializeObject(CBlockChain.Instance.RetriveBlock(Convert.ToUInt64(rqs.Data)).Header), rqs.ID)); break; } case ERequestType.NewTransaction: { Transaction t = JsonConvert.DeserializeObject <Transaction>(rqs.Data); if (t.Verify()) { MemPool.Instance.AddUTX(t); } break; } default: if (Program.DEBUG) { CIO.DebugOut("Ricevuto comando sconosciuto: " + rqs.RqsType + " da " + IP); } break; } } } }
/// <summary> /// Rimane in attesa di messaggi dal peer a cui è collegato il socket mSocket. /// </summary> private void Listen() { string tmp; CMessage msg; while (mIsConnected) //bisogna bloccarlo in qualche modo all'uscita del programma credo { lock (mSocket) { if (mSocket == null) { break; } //il timer viene settato cosicchè in caso non si ricevino comunicazioni venga ritornata un'eccezione, in modo che il programma vada avanti e tolga il lock al socket. mSocket.ReceiveTimeout = 1000; try { tmp = ReceiveString(); msg = JsonConvert.DeserializeObject <CMessage>(tmp); if (CValidator.ValidateMessage(msg)) { msg.TimeOfReceipt = DateTime.Now; if (msg.Type == EMessageType.Request) { lock (RequestQueue) { RequestQueue.Enqueue(msg); } } else if (msg.Type == EMessageType.Data && ValidID.Contains(msg.ID)) { lock (DataQueue) { DataQueue.Enqueue(msg); ValidID.Remove(msg.ID); } } else if (msg.Type == EMessageType.Disconnect) { this.Disconnect(); break; } else if (Program.DEBUG) { throw new ArgumentException("MessageType " + msg.Type + " non supportato."); } } else { Disconnect(); break; } } catch (SocketException) { } catch (JsonSerializationException) { throw new Exception(); Disconnect(); } //il timer viene reinpostato a defoult per non causare problemi con altre comunicazioni che potrebbero avvenire in altre parti del codice. mSocket.ReceiveTimeout = 0; } } }