Coverage Summary for Class: NetBlockStore (co.rsk.net)

Class Class, % Method, % Line, %
NetBlockStore 100% (1/1) 5.6% (1/18) 5.3% (5/95)


1 /* 2  * This file is part of RskJ 3  * Copyright (C) 2017 RSK Labs Ltd. 4  * 5  * This program is free software: you can redistribute it and/or modify 6  * it under the terms of the GNU Lesser General Public License as published by 7  * the Free Software Foundation, either version 3 of the License, or 8  * (at your option) any later version. 9  * 10  * This program is distributed in the hope that it will be useful, 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13  * GNU Lesser General Public License for more details. 14  * 15  * You should have received a copy of the GNU Lesser General Public License 16  * along with this program. If not, see <http://www.gnu.org/licenses/>. 17  */ 18  19 package co.rsk.net; 20  21 import org.ethereum.core.Block; 22 import org.ethereum.core.BlockHeader; 23 import co.rsk.crypto.Keccak256; 24  25 import javax.annotation.Nonnull; 26 import java.util.*; 27 import java.util.stream.Collectors; 28  29 /** 30  * Created by ajlopez on 5/11/2016. 31  */ 32 public class NetBlockStore { 33  private Map<Keccak256, Block> blocks = new HashMap<>(); 34  private Map<Long, Set<Block>> blocksbynumber = new HashMap<>(); 35  private Map<Keccak256, Set<Block>> blocksbyparent = new HashMap<>(); 36  37  private final Map<Keccak256, BlockHeader> headers = new HashMap<>(); 38  39  public synchronized void saveBlock(Block block) { 40  Keccak256 key = block.getHash(); 41  Keccak256 pkey = block.getParentHash(); 42  Long nkey = Long.valueOf(block.getNumber()); 43  this.blocks.put(key, block); 44  45  Set<Block> bsbynumber = this.blocksbynumber.get(nkey); 46  47  if (bsbynumber == null) { 48  bsbynumber = new HashSet<>(); 49  this.blocksbynumber.put(nkey, bsbynumber); 50  } 51  52  bsbynumber.add(block); 53  54  Set<Block> bsbyphash = this.blocksbyparent.get(pkey); 55  56  if (bsbyphash == null) { 57  bsbyphash = new HashSet<>(); 58  this.blocksbyparent.put(pkey, bsbyphash); 59  } 60  61  bsbyphash.add(block); 62  } 63  64  public synchronized void removeBlock(Block block) { 65  if (!this.hasBlock(block)) { 66  return; 67  } 68  69  Keccak256 key = block.getHash(); 70  Keccak256 pkey = block.getParentHash(); 71  Long nkey = Long.valueOf(block.getNumber()); 72  73  this.blocks.remove(key); 74  75  removeBlockByNumber(key, nkey); 76  removeBlockByParent(key, pkey); 77  } 78  79  private void removeBlockByParent(Keccak256 key, Keccak256 pkey) { 80  Set<Block> byparent = this.blocksbyparent.get(pkey); 81  82  if (byparent != null && !byparent.isEmpty()) { 83  Block toremove = null; 84  85  for (Block blk : byparent) { 86  if (blk.getHash().equals(key)) { 87  toremove = blk; 88  break; 89  } 90  } 91  92  if (toremove != null){ 93  byparent.remove(toremove); 94  95  if (byparent.isEmpty()) { 96  this.blocksbyparent.remove(pkey); 97  } 98  } 99  } 100  } 101  102  private void removeBlockByNumber(Keccak256 key, Long nkey) { 103  Set<Block> bynumber = this.blocksbynumber.get(nkey); 104  105  if (bynumber != null && !bynumber.isEmpty()) { 106  Block toremove = null; 107  108  for (Block blk : bynumber) { 109  if (blk.getHash().equals(key)) { 110  toremove = blk; 111  break; 112  } 113  } 114  115  if (toremove != null) { 116  bynumber.remove(toremove); 117  if (bynumber.isEmpty()) { 118  this.blocksbynumber.remove(nkey); 119  } 120  } 121  } 122  } 123  124  public synchronized Block getBlockByHash(byte[] hash) { 125  return this.blocks.get(new Keccak256(hash)); 126  } 127  128  public synchronized List<Block> getBlocksByNumber(long number) { 129  Set<Block> blockSet = this.blocksbynumber.get(Long.valueOf(number)); 130  if (blockSet == null) { 131  return new ArrayList<>(); 132  } 133  134  return new ArrayList<>(blockSet); 135  } 136  137  public synchronized List<Block> getBlocksByParentHash(Keccak256 hash) { 138  Set<Block> blockSet = this.blocksbyparent.get(hash); 139  if (blockSet == null) { 140  return new ArrayList<>(); 141  } 142  143  return new ArrayList<>(blockSet); 144  } 145  146  /** 147  * getChildrenOf returns all the children of a list of blocks that are in the BlockStore. 148  * 149  * @param blocks a set of blocks to retrieve the children. 150  * @return A list with all the children of the given list of blocks. 151  */ 152  public List<Block> getChildrenOf(Set<Block> blocks) { 153  return blocks.stream() 154  .flatMap(b -> getBlocksByParentHash(b.getHash()).stream()) 155  .distinct() 156  .collect(Collectors.toList()); 157  } 158  159  public synchronized boolean hasBlock(Block block) { 160  return this.blocks.containsKey(block.getHash()); 161  } 162  163  public synchronized boolean hasBlock(byte[] hash) { 164  return this.blocks.containsKey(new Keccak256(hash)); 165  } 166  167  public synchronized int size() { 168  return this.blocks.size(); 169  } 170  171  public synchronized long minimalHeight() { 172  long value = 0; 173  174  for (Block b : this.blocks.values()) { 175  if (value == 0 || b.getNumber() < value) { 176  value = b.getNumber(); 177  } 178  } 179  180  return value; 181  } 182  183  public synchronized long maximumHeight() { 184  long value = 0; 185  186  for (Block b : this.blocks.values()) { 187  if (value == 0 || b.getNumber() > value) { 188  value = b.getNumber(); 189  } 190  } 191  192  return value; 193  } 194  195  public synchronized void releaseRange(long from, long to) { 196  for (long k = from; k <= to; k++) { 197  for (Block b : this.getBlocksByNumber(k)) { 198  this.removeBlock(b); 199  } 200  } 201  } 202  203  /** 204  * hasHeader returns true if this block store has the header of the corresponding block. 205  * 206  * @return true if the store has the header, false otherwise. 207  * @param hash 208  */ 209  public synchronized boolean hasHeader(Keccak256 hash) { 210  return this.headers.containsKey(hash); 211  } 212  213  /** 214  * saveHeader saves the given header into the block store. 215  * 216  * @param header the header to store. 217  */ 218  public synchronized void saveHeader(@Nonnull final BlockHeader header) { 219  this.headers.put(header.getHash(), header); 220  } 221  222  /** 223  * removeHeader removes the given header from the block store. 224  * 225  * @param header the header to remove. 226  */ 227  public synchronized void removeHeader(@Nonnull final BlockHeader header) { 228  if (!this.hasHeader(header.getHash())) { 229  return; 230  } 231  232  this.headers.remove(header.getHash()); 233  } 234 }