public AddBlockResult Insert(Block block) { if (!CanAcceptNewBlocks) { return(AddBlockResult.CannotAccept); } if (block.Number == 0) { throw new InvalidOperationException("Genesis block should not be inserted."); } using (MemoryStream stream = Rlp.BorrowStream()) { Rlp.Encode(stream, block); byte[] newRlp = stream.ToArray(); _blockDb.Set(block.Hash, newRlp); } long expectedNumber = (LowestInsertedBody?.Number - 1 ?? LongConverter.FromString(_syncConfig.PivotNumber ?? "0")); if (block.Number != expectedNumber) { throw new InvalidOperationException($"Trying to insert out of order block {block.Number} when expected number was {expectedNumber}"); } if (block.Number < (LowestInsertedBody?.Number ?? long.MaxValue)) { LowestInsertedBody = block; } return(AddBlockResult.Added); }
public void Can_do_roundtrip_null_memory_stream() { using (MemoryStream stream = Rlp.BorrowStream()) { Rlp.Encode(stream, (Block)null); Block decoded = Rlp.Decode <Block>(stream.ToArray()); Assert.IsNull(decoded); } }
private static Keccak GetTruncatedHash(BlockHeader header) { using (MemoryStream stream = Rlp.BorrowStream()) { Rlp.Encode(stream, header, RlpBehaviors.ForSealing); Keccak headerHashed = Keccak.Compute(stream.ToArray()); // sic! Keccak here not Keccak512 return(headerHashed); } }
public static Keccak CalculateHash(BlockHeader header) { using (MemoryStream stream = Rlp.BorrowStream()) { Rlp.Encode(stream, header); byte[] buffer = _rlpBuffer.Value; stream.Seek(0, SeekOrigin.Begin); stream.Read(buffer, 0, (int)stream.Length); Keccak newOne = Keccak.Compute(buffer.AsSpan().Slice(0, (int)stream.Length)); return(newOne); } }
public AddBlockResult Insert(BlockHeader header) { if (!CanAcceptNewBlocks) { return(AddBlockResult.CannotAccept); } if (header.Number == 0) { throw new InvalidOperationException("Genesis block should not be inserted."); } // validate hash here using (MemoryStream stream = Rlp.BorrowStream()) { Rlp.Encode(stream, header); byte[] newRlp = stream.ToArray(); _headerDb.Set(header.Hash, newRlp); } BlockInfo blockInfo = new BlockInfo(header.Hash, header.TotalDifficulty ?? 0); try { _blockInfoLock.EnterWriteLock(); ChainLevelInfo chainLevel = new ChainLevelInfo(false, new[] { blockInfo }); PersistLevel(header.Number, chainLevel); } finally { _blockInfoLock.ExitWriteLock(); } if (header.Number < (LowestInsertedHeader?.Number ?? long.MaxValue)) { LowestInsertedHeader = header; } if (header.Number > BestKnownNumber) { BestKnownNumber = header.Number; } return(AddBlockResult.Added); }
public byte[] Serialize(BlockHeadersMessage message) { int contentLength = 0; for (int i = 0; i < message.BlockHeaders.Length; i++) { contentLength += _headerDecoder.GetLength(message.BlockHeaders[i], RlpBehaviors.None); } using (MemoryStream stream = Rlp.BorrowStream()) { Rlp.StartSequence(stream, contentLength); for (int i = 0; i < message.BlockHeaders.Length; i++) { _headerDecoder.Encode(stream, message.BlockHeaders[i]); } return(stream.ToArray()); } }
private AddBlockResult Suggest(Block block, BlockHeader header) { #if DEBUG /* this is just to make sure that we do not fall into this trap when creating tests */ if (header.StateRoot == null && !header.IsGenesis) { throw new InvalidDataException($"State root is null in {header.ToString(BlockHeader.Format.Short)}"); } #endif if (!CanAcceptNewBlocks) { return(AddBlockResult.CannotAccept); } if (_invalidBlocks.ContainsKey(header.Number) && _invalidBlocks[header.Number].Contains(header.Hash)) { return(AddBlockResult.InvalidBlock); } if (header.Number == 0) { if (BestSuggested != null) { throw new InvalidOperationException("Genesis block should be added only once"); } } else if (IsKnownBlock(header.Number, header.Hash)) { if (_logger.IsTrace) { _logger.Trace($"Block {header.Hash} already known."); } return(AddBlockResult.AlreadyKnown); } else if (!IsKnownBlock(header.Number - 1, header.ParentHash)) { if (_logger.IsTrace) { _logger.Trace($"Could not find parent ({header.ParentHash}) of block {header.Hash}"); } return(AddBlockResult.UnknownParent); } SetTotalDifficulty(header); if (block != null) { using (MemoryStream stream = Rlp.BorrowStream()) { Rlp.Encode(stream, block); byte[] newRlp = stream.ToArray(); _blockDb.Set(block.Hash, newRlp); } } using (MemoryStream stream = Rlp.BorrowStream()) { Rlp.Encode(stream, header); byte[] newRlp = stream.ToArray(); _headerDb.Set(header.Hash, newRlp); } BlockInfo blockInfo = new BlockInfo(header.Hash, header.TotalDifficulty ?? 0); try { _blockInfoLock.EnterWriteLock(); UpdateOrCreateLevel(header.Number, blockInfo); } finally { _blockInfoLock.ExitWriteLock(); } if (header.IsGenesis || header.TotalDifficulty > (BestSuggested?.TotalDifficulty ?? 0)) { BestSuggested = header; if (block != null) { BestSuggestedFullBlock = block.Header; NewBestSuggestedBlock?.Invoke(this, new BlockEventArgs(block)); } } return(AddBlockResult.Added); }
public AddBlockResult SuggestBlock(Block block) { #if DEBUG /* this is just to make sure that we do not fall into this trap when creating tests */ if (block.StateRoot == null && !block.IsGenesis) { throw new InvalidDataException($"State root is null in {block.ToString(Block.Format.Short)}"); } #endif if (!CanAcceptNewBlocks) { return(AddBlockResult.CannotAccept); } if (_invalidBlocks.ContainsKey(block.Number) && _invalidBlocks[block.Number].Contains(block.Hash)) { return(AddBlockResult.InvalidBlock); } if (block.Number == 0) { if (BestSuggested != null) { throw new InvalidOperationException("Genesis block should be added only once"); // TODO: make sure it cannot happen } } else if (IsKnownBlock(block.Number, block.Hash)) { if (_logger.IsTrace) { _logger.Trace($"Block {block.Hash} already known."); } return(AddBlockResult.AlreadyKnown); } else if (!IsKnownBlock(block.Number - 1, block.Header.ParentHash)) { if (_logger.IsTrace) { _logger.Trace($"Could not find parent ({block.Header.ParentHash}) of block {block.Hash}"); } return(AddBlockResult.UnknownParent); } using (MemoryStream stream = Rlp.BorrowStream()) { Rlp.Encode(stream, block); byte[] newRlp = stream.ToArray(); _blockDb.Set(block.Hash, newRlp); } // TODO: when reviewing the entire data chain need to look at the transactional storing of level and block SetTotalDifficulty(block); SetTotalTransactions(block); BlockInfo blockInfo = new BlockInfo(block.Hash, block.TotalDifficulty.Value, block.TotalTransactions.Value); try { _blockInfoLock.EnterWriteLock(); UpdateOrCreateLevel(block.Number, blockInfo); } finally { _blockInfoLock.ExitWriteLock(); } if (block.IsGenesis || block.TotalDifficulty > (BestSuggested?.TotalDifficulty ?? 0)) { BestSuggested = block.Header; NewBestSuggestedBlock?.Invoke(this, new BlockEventArgs(block)); } return(AddBlockResult.Added); }