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 }