Пример #1
0
        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));
        }
Пример #2
0
 protected override MerkleNode CreateNode(MerkleHash hash)
 {
     return(new DemoMerkleNode(hash));
 }
Пример #3
0
 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);
            }
        }
Пример #6
0
 public MerkleNode(string data)
 {
     Hash = new MerkleHash(data);
 }
Пример #7
0
        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);
            }
        }
Пример #8
0
 public static DemoMerkleNode Create(string s)
 {
     return(new DemoMerkleNode(MerkleHash.Create(s)));
 }
Пример #9
0
 public DemoMerkleNode(MerkleHash hash)
 {
     Hash = hash;
 }