private async Task <bool> SyncAndVerifyConsolidationBlockAsync(ILyraAPI client, ConsolidationBlock consBlock) { _log.LogInformation($"Sync and verify consolidation block height {consBlock.Height}"); foreach (var hash in consBlock.blockHashes) { if (!await SyncOneBlockAsync(client, hash)) { return(false); } } if (null != await _sys.Storage.FindBlockByHashAsync(consBlock.Hash)) { await _sys.Storage.RemoveBlockAsync(consBlock.Hash); } var mt = new MerkleTree(); foreach (var hash1 in consBlock.blockHashes) { mt.AppendLeaf(MerkleHash.Create(hash1)); } var merkelTreeHash = mt.BuildTree().ToString(); if (consBlock.MerkelTreeHash != merkelTreeHash) { _log.LogWarning($"SyncAndVerifyConsolidationBlock: consMerkelTree: {consBlock.MerkelTreeHash} mine: {merkelTreeHash}"); return(false); } // make sure no extra blocks here if (consBlock.Height > 1) { var prevConsHash = consBlock.blockHashes.First(); var prevConsResult = await client.GetBlockByHashAsync(_sys.PosWallet.AccountId, prevConsHash, null); if (prevConsResult.ResultCode != APIResultCodes.Success) { _log.LogWarning($"SyncAndVerifyConsolidationBlock: prevConsResult.ResultCode: {prevConsResult.ResultCode}"); return(false); } var prevConsBlock = prevConsResult.GetBlock() as ConsolidationBlock; if (prevConsBlock == null) { _log.LogWarning($"SyncAndVerifyConsolidationBlock: prevConsBlock: null"); return(false); } var blocksInTimeRange = await _sys.Storage.GetBlockHashesByTimeRangeAsync(prevConsBlock.TimeStamp, consBlock.TimeStamp); var q = blocksInTimeRange.Where(a => !consBlock.blockHashes.Contains(a)); foreach (var extraBlock in q) { await _sys.Storage.RemoveBlockAsync(extraBlock); } } return(await _sys.Storage.AddBlockAsync(consBlock)); }
protected override MerkleNode CreateNode(MerkleHash hash) { return(new DemoMerkleNode(hash)); }
public MerkleProofHash(MerkleHash hash, Branch direction) { Hash = hash; Direction = direction; }
protected override async Task <APIResultCodes> AuthorizeImplAsync <T>(DagSystem sys, T tblock) { if (!(tblock is ConsolidationBlock)) { return(APIResultCodes.InvalidBlockType); } var block = tblock as ConsolidationBlock; //// 1. check if the block already exists //if (null != await DagSystem.Singleton.Storage.GetBlockByUIndexAsync(block.UIndex)) // return APIResultCodes.BlockWithThisUIndexAlreadyExists; var lastCons = await sys.Storage.GetLastConsolidationBlockAsync(); if (block.Height > 1) { if (lastCons == null) { return(APIResultCodes.CouldNotFindLatestBlock); } // make sure the first hash is ALWAYS the previous consblock (except the first one) if (block.blockHashes.First() != lastCons.Hash) { return(APIResultCodes.InvalidConsolidationBlockContinuty); } var allHashes = (await sys.Storage.GetBlockHashesByTimeRangeAsync(lastCons.TimeStamp, block.TimeStamp)).ToList(); if (block.blockHashes.Count != allHashes.Count) { Console.WriteLine($"real count: {allHashes.Count} but block has: {block.blockHashes.Count}"); return(APIResultCodes.InvalidConsolidationBlockCount); } var mineNotYours = allHashes.Except(block.blockHashes).ToList(); var yoursNotMine = block.blockHashes.Except(allHashes).ToList(); if (mineNotYours.Any() || yoursNotMine.Any()) { return(APIResultCodes.InvalidConsolidationBlockHashes); } } // recalculate merkeltree // use merkle tree to consolidate all previous blocks, from lastCons.UIndex to consBlock.UIndex -1 var mt = new MerkleTree(); decimal feeAggregated = 0; foreach (var hash in block.blockHashes) { mt.AppendLeaf(MerkleHash.Create(hash)); // verify block exists if (null == await sys.Storage.FindBlockByHashAsync(hash)) { return(APIResultCodes.BlockNotFound); } // aggregate fees var transBlock = (await sys.Storage.FindBlockByHashAsync(hash)) as TransactionBlock; if (transBlock != null) { feeAggregated += transBlock.Fee; } } var mkhash = mt.BuildTree().ToString(); if (block.MerkelTreeHash != mkhash) { return(APIResultCodes.InvalidConsolidationMerkleTreeHash); } if (block.totalFees != feeAggregated.ToBalanceLong()) { return(APIResultCodes.InvalidConsolidationTotalFees); } // consolidation must come from leader node // done in base authorizer already! return(await Lyra.Shared.StopWatcher.TrackAsync(() => base.AuthorizeImplAsync(sys, tblock), "ConsolidationBlockAuthorizer->BaseAuthorizer")); }
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); } }
public MerkleNode(string data) { Hash = new MerkleHash(data); }
protected void DrawConsistencyProof(MerkleTree tree, DemoMerkleNode oldTreeRoot, int m, MerkleHash newRootHash) { tree.RootNode.Leaves().Cast <DemoMerkleNode>().Take(m).ForEach(n => Highlight(n, "Orange")); List <MerkleProofHash> proofToOldRoot = tree.ConsistencyProof(m); bool ret = MerkleTree.VerifyConsistency(oldTreeRoot.Hash, proofToOldRoot); lblConsistencyPassFail.Text = ret ? "Pass" : "Fail"; lblConsistencyPassFail.ForeColor = ret ? Color.Green : Color.Red; tbConsistencyTrail.Clear(); proofToOldRoot.ForEach(hash => { var node = tree.RootNode.Cast <DemoMerkleNode>().First(t => t.Hash == hash.Hash); Highlight(node); tbConsistencyTrail.AppendText(node.Text + CRLF); }); tbConsistencyTrail.AppendText(oldTreeRoot.Text + " = old root" + CRLF); if (!ckOnlyToOldRoot.Checked) { // The remainder: consistency audit proof. var lastNode = proofToOldRoot.Last(); List <MerkleProofHash> proofToNewRoot = tree.ConsistencyAuditProof(lastNode.Hash); foreach (var auditHash in proofToNewRoot) { // We use First because a tree with an odd number of leaves will duplicate the last leaf // when computing the hash. var n = tree.RootNode.Cast <DemoMerkleNode>().First(t => t.Hash == auditHash.Hash); // tbAuditTrail.AppendText(n.Text + CRLF); if (!proofToOldRoot.Any(ph => ph.Hash == n.Hash)) { Highlight(n, "Purple"); } } var auditPairs = MerkleTree.AuditHashPairs(lastNode.Hash, proofToNewRoot); string lastHash = ""; foreach (var pair in auditPairs) { var left = tree.RootNode.Cast <DemoMerkleNode>().First(t => t.Hash == pair.Item1); var right = tree.RootNode.Cast <DemoMerkleNode>().First(t => t.Hash == pair.Item2); lastHash = left.Text + right.Text; tbConsistencyTrail.AppendText(left.Text + " + " + right.Text + " = " + lastHash + CRLF); } tbConsistencyTrail.AppendText(lastHash + " = new root" + CRLF); } }
public static DemoMerkleNode Create(string s) { return(new DemoMerkleNode(MerkleHash.Create(s))); }
public DemoMerkleNode(MerkleHash hash) { Hash = hash; }