public bool Connect(int Timeout) { if (Program.DEBUG) { CIO.DebugOut("Connecting to " + mIp + ":" + mPort); } SocketAsyncEventArgs asyncConnection = new SocketAsyncEventArgs(); bool SuccessfulConnected = false; asyncConnection.Completed += (object sender, SocketAsyncEventArgs e) => { SuccessfulConnected = true; }; asyncConnection.RemoteEndPoint = new IPEndPoint(mIp, mPort); mSocket.ConnectAsync(asyncConnection); Thread.Sleep(Timeout); if (SuccessfulConnected) { if (Program.DEBUG) { CIO.DebugOut("Connection with " + mIp + ":" + mPort + " enstablished!"); } mIsConnected = true; StartListening(); return(true); } else { if (Program.DEBUG) { CIO.DebugOut("Connection with " + mIp + ":" + mPort + " failed!"); } mSocket.Close(); mSocket.Dispose(); asyncConnection.Dispose(); return(false); } }
/// <summary> /// Aggiunge il proof of work(l'hash) al blocco. /// </summary> /// <param name="Block">Blocco su cui calcolare il proof of work.</param> public static void AddProof(CBlock Block) //TODO: implementare evento per l'uscita in caso sia stato trovato un blocco parallelo. Implementare multithreading { string hash = ""; bool found = false; while (!found) { Block.Timestamp = DateTime.Now; Block.Nonce++; //incremento della nonce per cambiare hash hash = HashBlock(Block); //calcola l'hash secondo il template di scrypt usato da litecoin found = true; for (int i = 0; i < Block.Difficulty && found; i++) { if (hash[i] != '0') { found = false; } } } if (Program.DEBUG) { CIO.DebugOut("Found hash for block " + Block.Header.BlockNumber + ": " + hash); } Block.Header.Hash = hash; }
private void SendString(string Msg) { SendData(ASCIIEncoding.ASCII.GetBytes(Msg)); if (Program.DEBUG) { CIO.DebugOut("Sent string " + Msg + "."); } }
//sincronizza la blockchain public void SyncBlockchain() { if (Program.DEBUG) { CIO.DebugOut("Start update blockchain..."); } mThreadSyncBlockChain = new Thread(new ThreadStart(UpdateBlockchain)); mThreadSyncBlockChain.Name = "SyncBlockchain"; mThreadSyncBlockChain.Start(); }
private string ReceiveString() { string msg = ASCIIEncoding.ASCII.GetString(Receive()); if (Program.DEBUG) { CIO.DebugOut("Received string " + msg + "."); } return(msg); }
//attende il collegamento di nuovi peer private void StartAcceptUsersConnection() { if (Program.DEBUG) { CIO.DebugOut("Initialize the Listener..."); } //crea un socket che attende connessioni in ingresso di peer che vogliono collegarsi, in ascolto sulla porta DEFOULT_PORT IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, DEFAULT_PORT); mListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); mListener.Bind(localEndPoint); mListener.Listen(DEFAULT_PORT); //crea un eventargs per una richiesta di connessione asincrona, se la lista dei peers non è ancora piena inizia ad attendere fino a quando non riceve //una richiesta di connessione o il segnale d'arresto. Se viene ricevuta una richiesta di connessione viene chiamata la funzione InsertNewPeer che //inserisce il nuovo peer nella lista dei peer mPeers //è asincrono perchè altrimenti al segnale di spegnimento non si fermerebbe SocketAsyncEventArgs asyncConnection; bool IncomingConnection = false; if (Program.DEBUG) { CIO.DebugOut("Attending connection..."); } while (!IsStopped) { if (ConnectedPeers < MAX_PEERS) { IncomingConnection = false; asyncConnection = new SocketAsyncEventArgs(); asyncConnection.Completed += (object sender, SocketAsyncEventArgs e) => { IncomingConnection = true; }; mListener.AcceptAsync(asyncConnection); while (!IncomingConnection && !IsStopped) { Thread.Sleep(1000); } if (IncomingConnection) { if (Program.DEBUG) { CIO.DebugOut("Established connection with " + ((IPEndPoint)asyncConnection.AcceptSocket.RemoteEndPoint).Address + " !"); } InsertNewPeer(asyncConnection.AcceptSocket); } asyncConnection.Dispose(); } else { Thread.Sleep(10000); } } }
//avvia il thread del miner public void StartMining() { if (mThreadMiner == null) { if (Program.DEBUG) { CIO.DebugOut("Start Miner..."); } mThreadMiner = new Thread(new ThreadStart(StartMiner)); mThreadMiner.Name = "Miner"; mThreadMiner.Start(); } }
private void UpdatePeers() { int id; string[] listsPeer; string[] peers; string msg = ""; string ris = ""; CPeer receivedPeer; foreach (CPeer p in Peers) { try { id = p.SendRequest(new CMessage(EMessageType.Request, ERequestType.UpdPeers)); msg = p.ReceiveData(id, 5000).Data; ris += msg + "/"; } catch { if (Program.DEBUG) { CIO.DebugOut("Nessuna risposta da " + p.IP + " durante la richiesta dei peer." + "Disconnessione da " + p.IP); } p.Disconnect(); } } ris = ris.TrimEnd('/'); if (ris != "") { string publicIp = CServer.GetPublicIPAddress(); string localIp = CServer.GetLocalIPAddress(); listsPeer = ris.Split('/'); foreach (string l in listsPeer) { peers = l.Split(';'); foreach (string rp in peers) { receivedPeer = CPeer.Deserialize(rp); if (!(receivedPeer.IP == publicIp || receivedPeer.IP == localIp)) { Insert(receivedPeer); } } } } }
public static string GetPublicIPAddress() { try { if (mPublicIp == "") { mPublicIp = new WebClient().DownloadString("http://icanhazip.com"); } return(mPublicIp.Trim('\n')); } catch { if (Program.DEBUG) { CIO.DebugOut("Error: can't get public ip."); } return(""); } }
private bool IsStopped = false; //set true per fermare il server private CServer() { rsaKeyPair = RSA.GenRSAKey(); // crea oggetto CSP per generare o caricare il keypair if (File.Exists(RSA.PATH + "\\keystore.xml")) // Se il file di keystore esiste viene caricato in memoria dal disco, altrimenti viene creato e salvato su disco { string xmlString = File.ReadAllText(RSA.PATH + "\\keystore.xml"); rsaKeyPair.FromXmlString(xmlString); } else//se il file non esiste ne viene generato uno { string xmlString = rsaKeyPair.ToXmlString(true); File.WriteAllText(RSA.PATH + "\\keystore.xml", xmlString); } if (Program.DEBUG) { CIO.DebugOut("Last block number: " + CBlockChain.Instance.LastValidBlock.Header.BlockNumber + "."); } }
public void InitializePeersList(List <CPeer> peers) { if (Program.DEBUG) { CIO.DebugOut("Initialize mPeers..."); } mPeers = new CPeers(MAX_PEERS, RESERVED_CONNECTION); if (Program.DEBUG) { CIO.DebugOut("Begin to enstablish connections to initial peers..."); } //si collega ai peer inseriti nella lista iniziale. foreach (CPeer p in peers) { if (p.Connect(500)) { if (!mPeers.Insert(p)) { break; } } } if (Program.DEBUG) { CIO.DebugOut("Begin to enstablish connections to other peers..."); } mThreadUpdatePeers = new Thread(new ThreadStart(UpdatePeersList)); mThreadUpdatePeers.Name = "mUpdatePeers"; mThreadUpdatePeers.Start(); if (Program.DEBUG) { CIO.DebugOut("Start listening..."); } mThreadListener = new Thread(new ThreadStart(StartAcceptUsersConnection)); mThreadListener.Name = "Listener"; mThreadListener.Start(); }
public static short CalculateDifficulty() { int numberOfBlocks = 300; CBlock lastBlock = CBlockChain.Instance.LastBlock; CBlock previousBlock; short newBlockDifficulty = 0; ulong highAverangeTimeLimit = 70, lowAverangeTimeLimit = 30; ulong averangeBlockTime = 0; if (lastBlock.Header.BlockNumber > (ulong)numberOfBlocks) { previousBlock = CBlockChain.Instance.RetriveBlock(lastBlock.Header.BlockNumber - (ulong)numberOfBlocks, true); } else { previousBlock = CBlockChain.Instance.RetriveBlock(1, true); } if (previousBlock != null) { averangeBlockTime = CBlockChain.Instance.AverageBlockTime(previousBlock, lastBlock); //in secondi } else { averangeBlockTime = 60; } if (averangeBlockTime > highAverangeTimeLimit) { newBlockDifficulty = (short)(lastBlock.Difficulty - 1); if (newBlockDifficulty <= 0) { newBlockDifficulty = 1; } if (Program.DEBUG) { CIO.DebugOut("La nuova difficoltà è: " + newBlockDifficulty); //Thread.Sleep(1000); } } else if (averangeBlockTime < lowAverangeTimeLimit) { newBlockDifficulty = (short)(lastBlock.Difficulty + 1); if (newBlockDifficulty >= 4) { newBlockDifficulty = 4; } if (Program.DEBUG) { CIO.DebugOut("La nuova difficoltà è: " + newBlockDifficulty); //Thread.Sleep(1000); } } else { newBlockDifficulty = (short)lastBlock.Difficulty; if (Program.DEBUG) { CIO.DebugOut("La nuova difficoltà è: " + newBlockDifficulty); //Thread.Sleep(1000); } } return(3); }
static void Main(string[] args) { //Apre il canale di comunicazione per GUI https://github.com/Kojee/BlockChainGUI OpenWCFServices(); //List<CPeer> lp = GenPeersList(); List <CPeer> lp = new List <CPeer>(); CIO.WriteLine("Enter the peer address:"); string firstPeerIP = Console.ReadLine(); try { if (!IPAddress.TryParse(firstPeerIP, out var IP)) { firstPeerIP = "192.168.1.1"; } } catch { firstPeerIP = "192.168.1.1"; } lp.Add(CPeer.CreatePeer(firstPeerIP, 4000)); CServer.Instance.InitializePeersList(lp); Services cmd = new Services(); bool b = true; while (b) { string command = Console.ReadLine().ToLower(); switch (command) { case "transaction": { CIO.WriteLine("Enter destination address:"); string hashReceiver = Console.ReadLine(); CIO.WriteLine("Enter the amout of coins to send:"); double amount = Convert.ToDouble(Console.ReadLine()); Transaction tx = new Transaction(amount, hashReceiver, CServer.rsaKeyPair); break; } case "miner": { CServer.Instance.StartMining(); break; } case "sync": { CServer.Instance.SyncBlockchain(); break; } case "address": { CIO.WriteLine(cmd.GetKeystore()); break; } case "balance": { CIO.WriteLine(cmd.GetBalance().ToString()); break; } case "stop": { b = false; Environment.Exit(1); break; } default: { CIO.WriteLine("Invalid command."); break; } } } }
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; } } } }