public StateFixture() { f = new Final(); h = new Hnv(); pd = new Prepared(); ppd = new PrePrepared(); vcd = new ViewChanged(); v = new View(); }
private IMessage ProcessMessage(State s, ulong sender, ulong receiver, BlockID origin, IMessage msg) { var(node, round) = msg.NodeRound(); if (s.Data.ContainsKey(new Final(node, round))) { return(null); } var v = s.GetView(node, round); Debug.WriteLine($"Processing message from block block.id={origin} message={msg}"); switch (msg) { case PrePrepare m: if (v != m.View) { return(null); } var pp = new PrePrepared(node, round, m.View); if (s.Data.ContainsKey(pp)) { return(null); } ulong size = sender > receiver ? sender : receiver; // var b = s.GetBitSet(NodeCount, m); var b = s.GetBitSet((int)size, m); b.SetPrepare(sender); b.SetPrepare(receiver); if (s.Data == null) { s.Data = new StateKV() { { pp, m } }; } else { s.Data[pp] = m; } return(new Prepare(m.Hash, node, round, receiver, m.View)); case Prepare m: if (v > m.View) { return(null); } if (v < m.View) { // b = s.GetBitSet(NodeCount, m.Pre()); b = s.GetBitSet((int)sender, m.Pre()); b.SetPrepare(m.Sender); return(null); } // b = s.GetBitSet(NodeCount, m.Pre()); b = s.GetBitSet((int)sender, m.Pre()); b.SetPrepare(m.Sender); Debug.WriteLine($"Prepare count == {b.PrepareCount()}"); if (b.PrepareCount() != Quorum2f1) { return(null); } if (b.HasCommit(receiver)) { return(null); } b.SetCommit(receiver); var p = new Prepared(node, round, m.View); if (!s.Data.ContainsKey(p)) { if (s.Data == null) { s.Data = new StateKV() { { p, m.Hash } }; } else { s.Data[p] = m.Hash; } } return(new Commit(m.Hash, node, round, receiver, m.View)); case Commit m: if (v < m.View) { return(null); } // b = s.GetBitSet(NodeCount, m.Pre()); b = s.GetBitSet((int)sender, m.Pre()); b.SetCommit(m.Sender); Debug.WriteLine($"Commit count == {b.CommitCount()}"); if (b.CommitCount() != Quorum2f1) { return(null); } var nr = new NodeRound(node, round); if (s.Final.ContainsKey(nr)) { return(null); } if (s.Final == null) { s.Final = new Dictionary <NodeRound, string>() { { nr, m.Hash } }; } else { s.Final[nr] = m.Hash; } Deliver(node, round, m.Hash); return(null); case ViewChange m: if (v > m.View) { return(null); } Dictionary <ulong, string> vcs; var key = new ViewChanged(node, round, v); if (s.Data.ContainsKey(key)) { var val = s.Data[key]; vcs = (Dictionary <ulong, string>)val; } else { vcs = new Dictionary <ulong, string>(); if (s.Data == null) { s.Data = new StateKV() { { key, vcs } }; } else { s.Data[key] = vcs; } } vcs[m.Sender] = m.Hash; if (vcs.Count != Quorum2f1) { return(null); } s.Data[new View(node, round)] = m.View; var hash = ""; foreach (KeyValuePair <ulong, string> item in vcs) { var hval = item.Value; if (hval != "") { if (hash != "" && hval != hash) { Console.WriteLine($"Got multiple hashes in a view change node.id={node} round={round} hash={hash} hash.alt={hval}"); } hash = hval; } } return(new NewView(hash, node, round, receiver, m.View)); case NewView m: if (v > m.View) { return(null); } var viewKey = new Hnv(node, round, m.View); if (s.Data.ContainsKey(viewKey)) { return(null); } if (s.Data == null) { s.Data = new StateKV(); } s.Data[new View(node, round)] = m.View; var tval = origin.Round + s.Timeout + 5; if (!s.Timeouts.ContainsKey(tval)) { s.Timeouts[tval] = new List <Timeout>(); } s.Timeouts[tval].Add(new Timeout(node, round, m.View)); s.Data[viewKey] = true; return(new PrePrepare(m.Hash, node, round, m.View)); default: throw new Exception($"blockmania: unknown message kind to process: {msg.Kind()}"); } }
/// <summary> /// /// </summary> /// <param name="s"></param> /// <param name="sender"></param> /// <param name="receiver"></param> /// <param name="origin"></param> /// <param name="msg"></param> /// <returns></returns> /// <exception cref="Exception"></exception> private IMessage ProcessMessage(State s, ulong sender, ulong receiver, Block origin, IMessage msg) { _logger.Here().Debug("State: {@State}, Sender: {@Sender}, Receiver: {@Receiver}, Origin: {@Origin}, Message: {@Message}", s, sender.ToString(), receiver.ToString(), origin, msg); var(node, round) = msg.NodeRound(); if (s.Data.ContainsKey(new Final(node, round))) { _logger.Here().Debug("State contains final, node: {@Node}, round: {@Round}", node, round); return(null); } var v = s.GetView(node, round); _logger.Here().Debug("Processing message from block block.id: {@BlockID}, message: {@Message}", origin, msg); switch (msg) { case PrePrepare m: if (v != m.View) { return(null); } var pp = new PrePrepared(node, round, m.View); if (s.Data.ContainsKey(pp)) { return(null); } var size = sender > receiver ? sender : receiver; // var b = s.GetBitSet(NodeCount, m); var b = s.GetBitSet((int)size, m); b.SetPrepare(sender); b.SetPrepare(receiver); if (s.Data == null) { s.Data = new StateKV { { pp, m } }; } else { s.Data[pp] = m; } _logger.Here().Debug("PrePrepare, node: {@Node}, round: {@Round}, sender: {@Sender}, hash: {@Hash}", node.ToString(), round.ToString(), receiver.ToString(), m.Hash); return(new Prepare(m.Hash, node, round, receiver, m.View)); case Prepare m: if (v > m.View) { return(null); } if (v < m.View) { // b = s.GetBitSet(NodeCount, m.Pre()); b = s.GetBitSet((int)sender, m.Pre()); b.SetPrepare(m.Sender); return(null); } // b = s.GetBitSet(NodeCount, m.Pre()); b = s.GetBitSet((int)sender, m.Pre()); b.SetPrepare(m.Sender); _logger.Here().Debug("Prepare count: {@PrepareCount}", b.PrepareCount()); if (b.PrepareCount() != Quorum2f1) { return(null); } if (b.HasCommit(receiver)) { return(null); } b.SetCommit(receiver); var p = new Prepared(node, round, m.View); if (s.Data.ContainsKey(p)) { return(new Commit(m.Hash, node, round, receiver, m.View)); } if (s.Data == null) { s.Data = new StateKV() { { p, m.Hash } }; } else { s.Data[p] = m.Hash; } _logger.Here().Debug("Prepare, node: {@Node}, round: {@Round}, sender: {@Sender}, hash: {@Hash}", node.ToString(), round.ToString(), receiver.ToString(), m.Hash); return(new Commit(m.Hash, node, round, receiver, m.View)); case Commit m: if (v < m.View) { return(null); } // b = s.GetBitSet(NodeCount, m.Pre()); b = s.GetBitSet((int)sender, m.Pre()); b.SetCommit(m.Sender); _logger.Here().Debug("Commit count: {@CommitCount}", b.CommitCount()); if (b.CommitCount() != Quorum2f1) { return(null); } var nr = new NodeRound(node, round); if (s.Final.ContainsKey(nr)) { return(null); } if (s.Final == null) { s.Final = new Dictionary <NodeRound, string>() { { nr, m.Hash } }; } else { s.Final[nr] = m.Hash; } _logger.Here().Debug("Deliver, node: {@Node}, round: {@Round}, hash: {@Hash}", node.ToString(), round.ToString(), m.Hash); Deliver(node, round, m.Hash); return(null); case ViewChange m: if (v > m.View) { return(null); } Dictionary <ulong, string> vcs; var key = new ViewChanged(node, round, v); if (s.Data.ContainsKey(key)) { var val = s.Data[key]; vcs = (Dictionary <ulong, string>)val; } else { vcs = new Dictionary <ulong, string>(); if (s.Data == null) { s.Data = new StateKV() { { key, vcs } }; } else { s.Data[key] = vcs; } } vcs[m.Sender] = m.Hash; if (vcs.Count != Quorum2f1) { return(null); } s.Data[new View(node, round)] = m.View; var hash = ""; foreach (var hval in vcs.Select(item => item.Value).Where(hval => hval != "")) { if (hash != "" && hval != hash) { _logger.Here().Debug("Got multiple hashes in a view change node.id: {@Node}, round: {Round}, hash={@Hash} hash.alt={@HashAlt}", node.ToString(), round.ToString(), hash, hval); } hash = hval; } _logger.Here().Debug("ViewChange, node: {@Node}, round: {@Round}, sender: {@Sender}, hash: {@Hash}", node.ToString(), round.ToString(), receiver.ToString(), m.Hash); return(new NewView(hash, node, round, receiver, m.View)); case NewView m: if (v > m.View) { return(null); } var viewKey = new Hnv(node, round, m.View); if (s.Data.ContainsKey(viewKey)) { return(null); } s.Data ??= new StateKV(); s.Data[new View(node, round)] = m.View; var tval = origin.Round + s.Timeout + 5; if (!s.Timeouts.ContainsKey(tval)) { s.Timeouts[tval] = new List <Timeout>(); } s.Timeouts[tval].Add(new Timeout(node, round, m.View)); s.Data[viewKey] = true; _logger.Here().Debug("NewView -> PrePrepare, node: {@Node}, round: {@Round}, hash: {@Hash}", node.ToString(), round.ToString(), m.Hash); return(new PrePrepare(m.Hash, node, round, m.View)); default: throw new Exception($"blockmania: unknown message kind to process: {msg.Kind()}"); } }