private static List <HeadCandidate> AssembleBlockchain(Database db, HeadSelector selector) { var blocks = BuildBlocks(db); var ret = new List <HeadCandidate>(blocks.Blocks.Count); if (blocks.Blocks.Count == 0) { return(ret); } for (var current = SelectHead(db, blocks, selector); current != null; current = current.Previous) { ret.Add(current); var back = ret[ret.Count - 1]; if (current.Previous != null) { back.PreviousBlockId = current.Previous.DbId; } else { back.PreviousBlockId = long.MaxValue; } } ret.Reverse(); return(ret); }
private static HeadCandidate SelectHead(Database db, BlocksTemp blocks, HeadSelector selector) { var heads = blocks.Blocks.Where(block => !block.HasChildren).ToList(); if (heads.Count == 0) { throw new Exception("Invalid blockchain. Circular topologies are invalid."); } if (heads.Count == 1) { return(heads[0]); } var hash = db.BlockchainHead; if (hash == null) { if (selector == null) { throw new Exception("Can't read blockchain head from DB."); } hash = selector(heads).Hash; } HeadCandidate ret; if (!blocks.BlockMap.TryGetValue(hash, out ret)) { throw new Exception( $"DB states that the blockchain head is {hash}, but no such block exists in the DB."); } return(ret); }
public Blockchain(Database db, HeadSelector selector = null) : base(db, Configuration.Get().Network) { var blocks = AssembleBlockchain(db, selector); _blockchain = new List <Block>(blocks.Count); foreach (var block in blocks) { var height = _blockchain.Count; var block2 = new Block { Hash = block.Hash, PreviousHash = block.PreviousHash, Height = height, DbId = block.DbId, PreviousBlockId = block.PreviousBlockId }; _blockMap[block2.Hash] = height; _blockchain.Add(block2); } UpdateDb(); }