private void CheckAuthorizedAllOk(AuthState state) { if (state.GetIsAuthoringSuccess(_board)) { if (state.Saving) { return; } state.Saving = true; _ = Task.Run(() => { // do commit var block = state.InputMsg.Block; block.Authorizations = state.OutputMsgs.Select(a => a.AuthSign).ToList(); if (block.BlockType != BlockTypes.Consolidation) { // pickup UIndex try { block.UIndex = state.ConsensusUIndex; } catch (Exception ex) { _log.LogError("Can't get UIndex. System fail: " + ex.Message); return; } } if (block.UIndex != _UIndexSeed - 1) { // local node out of sync _UIndexSeed = block.UIndex + 1; Mode = ConsensusWorkingMode.OutofSyncWaiting; LyraSystem.Singleton.TheBlockchain.Tell(new BlockChain.NeedSync { ToUIndex = block.UIndex }); } block.UHash = SignableObject.CalculateHash($"{block.UIndex}|{block.Index}|{block.Hash}"); BlockChain.Singleton.AddBlock(block); var msg = new AuthorizerCommitMsg { From = NodeService.Instance.PosWallet.AccountId, MsgType = ChatMessageType.AuthorizerCommit, BlockHash = state.InputMsg.Block.Hash, BlockIndex = block.UIndex, Commited = true }; state.AddCommitedResult(msg); Send2P2pNetwork(msg); _log.LogInformation($"Consensus: OnPrepare Commited: BlockUIndex: {msg.BlockHash}"); }); } }
public ConsensusService(IActorRef localNode) { _localNode = localNode; _log = new SimpleLogger("ConsensusService").Logger; _outOfOrderedMessages = new Dictionary <string, List <SourceSignedMessage> >(); _activeConsensus = new Dictionary <string, AuthState>(); _authorizers = new AuthorizersFactory(); while (BlockChain.Singleton == null) { Task.Delay(100).Wait(); } _UIndexSeed = BlockChain.Singleton.GetBlockCount() + 1; Mode = ConsensusWorkingMode.OutofSyncWaiting; Receive <Consolidate>((_) => { _log.LogInformation("Doing Consolidate"); OnNodeActive(NodeService.Instance.PosWallet.AccountId); // update billboard if (Mode == ConsensusWorkingMode.Normal) { BroadCastBillBoard(); GenerateConsolidateBlock(); } }); Receive <BillBoard>((bb) => { _board = bb; }); Receive <AskForBillboard>((_) => Sender.Tell(_board)); Receive <AuthorizingMsg>(async msg => { if (msg.Version != LyraGlobal.ProtocolVersion) { Sender.Tell(null); } OnNodeActive(NodeService.Instance.PosWallet.AccountId); // update billboard // first try auth locally var state = CreateAuthringState(msg); var localAuthResult = LocalAuthorizingAsync(msg); state.AddAuthResult(localAuthResult); if (!localAuthResult.IsSuccess) { state.Done.Set(); Sender.Tell(state); } else { Send2P2pNetwork(msg); Send2P2pNetwork(localAuthResult); var sender = Context.Sender; await Task.Run(() => { _ = state.Done.WaitOne(); }).ConfigureAwait(false); sender.Tell(state); } }); Receive <SignedMessageRelay>(relayMsg => { if (relayMsg.signedMessage.Version == LyraGlobal.ProtocolVersion) { OnNextConsensusMessage(relayMsg.signedMessage); } else { _log.LogWarning("Protocol Version Mismatch. Do nothing."); } }); Receive <BlockChainSynced>(_ => { Mode = ConsensusWorkingMode.Normal; _UIndexSeed = BlockChain.Singleton.GetBlockCount() + 1; // declare to the network var msg = new ChatMsg { From = NodeService.Instance.PosWallet.AccountId, MsgType = ChatMessageType.NodeUp, Text = "Staking with () Lyra" }; Send2P2pNetwork(msg); }); Task.Run(async() => { while (true) { StateClean(); await Task.Delay(1000).ConfigureAwait(false); } }); }
private void GenerateConsolidateBlock() { var authGenesis = BlockChain.Singleton.GetLastServiceBlock(); var lastCons = BlockChain.Singleton.GetSyncBlock(); var consBlock = new ConsolidationBlock { UIndex = _UIndexSeed++, NetworkId = authGenesis.NetworkId, ShardId = authGenesis.ShardId, ServiceHash = authGenesis.Hash, SvcAccountID = NodeService.Instance.PosWallet.AccountId }; // use merkle tree to consolidate all previous blocks, from lastCons.UIndex to consBlock.UIndex -1 var mt = new MerkleTree(); for (var ndx = lastCons.UIndex; ndx < consBlock.UIndex; ndx++) // TODO: handling "losing" block here { var block = BlockChain.Singleton.GetBlockByUIndex(ndx); if (block == null) { // block lost _log.LogError($"Block lost for No. {ndx}. Try to resync with other seeds..."); // triggering a resync Mode = ConsensusWorkingMode.OutofSyncWaiting; LyraSystem.Singleton.TheBlockchain.Tell(new BlockChain.NeedSync { ToUIndex = ndx }); return; } var mhash = MerkleHash.Create(block.UHash); mt.AppendLeaf(mhash); } consBlock.MerkelTreeHash = mt.BuildTree().ToString(); consBlock.InitializeBlock(lastCons, NodeService.Instance.PosWallet.PrivateKey, authGenesis.NetworkId, authGenesis.ShardId, NodeService.Instance.PosWallet.AccountId); //consBlock.UHash = SignableObject.CalculateHash($"{consBlock.UIndex}|{consBlock.Index}|{consBlock.Hash}"); //consBlock.Authorizations = new List<AuthorizationSignature>(); //consBlock.Authorizations.Add(new AuthorizationSignature //{ // Key = NodeService.Instance.PosWallet.AccountId, // Signature = Signatures.GetSignature(NodeService.Instance.PosWallet.PrivateKey, consBlock.Hash + consBlock.ServiceHash, NodeService.Instance.PosWallet.AccountId) //}); //BlockChain.Singleton.AddBlock(consBlock); //// broadcast to whole network //var msg = new ChatMsg(NodeService.Instance.PosWallet.AccountId, JsonConvert.SerializeObject(consBlock)); //msg.MsgType = ChatMessageType.BlockConsolidation; //Send2P2pNetwork(msg); // no, we do consensus AuthorizingMsg msg = new AuthorizingMsg { From = NodeService.Instance.PosWallet.AccountId, Block = consBlock, MsgType = ChatMessageType.AuthorizerPrePrepare }; var state = CreateAuthringState(msg); var localAuthResult = LocalAuthorizingAsync(msg); state.AddAuthResult(localAuthResult); if (!localAuthResult.IsSuccess) { _log.LogError("Fatal Error: Consolidate block local authorization failed."); } else { Send2P2pNetwork(msg); Send2P2pNetwork(localAuthResult); } }