Added missing merge files.
This commit is contained in:
parent
74eca228dc
commit
e376bfc922
|
@ -0,0 +1,16 @@
|
||||||
|
package org.ethereum.datasource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mikhail Kalinin
|
||||||
|
* @since 07.07.2015
|
||||||
|
*/
|
||||||
|
public interface DataSource {
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
void setName(String name);
|
||||||
|
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
void close();
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package org.ethereum.datasource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mikhail Kalinin
|
||||||
|
* @since 07.07.2015
|
||||||
|
*/
|
||||||
|
public interface QueueDataSource extends DataSource {
|
||||||
|
|
||||||
|
void offerFirst(byte[] e);
|
||||||
|
|
||||||
|
byte[] peekFirst();
|
||||||
|
|
||||||
|
byte[] pollFirst();
|
||||||
|
|
||||||
|
void offerLast(byte[] e);
|
||||||
|
|
||||||
|
byte[] peekLast();
|
||||||
|
|
||||||
|
byte[] pollLast();
|
||||||
|
|
||||||
|
boolean isEmpty();
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
package org.ethereum.datasource.mapdb;
|
||||||
|
|
||||||
|
import org.ethereum.config.SystemProperties;
|
||||||
|
import org.ethereum.datasource.QueueDataSource;
|
||||||
|
import org.mapdb.BTreeMap;
|
||||||
|
import org.mapdb.DB;
|
||||||
|
import org.mapdb.DBMaker;
|
||||||
|
import org.mapdb.Serializer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import static java.lang.System.getProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mikhail Kalinin
|
||||||
|
* @since 07.07.2015
|
||||||
|
*/
|
||||||
|
public class MapDBQueueDataSource implements QueueDataSource {
|
||||||
|
|
||||||
|
private DB db;
|
||||||
|
private BTreeMap<Long, byte[]> map;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
File dbFile = new File(getProperty("user.dir") + "/" + SystemProperties.CONFIG.databaseDir() + "/" + name);
|
||||||
|
if (!dbFile.getParentFile().exists()) dbFile.getParentFile().mkdirs();
|
||||||
|
|
||||||
|
db = DBMaker.fileDB(dbFile)
|
||||||
|
.transactionDisable()
|
||||||
|
.closeOnJvmShutdown()
|
||||||
|
.make();
|
||||||
|
|
||||||
|
map = db.treeMapCreate(name)
|
||||||
|
.keySerializer(Serializer.LONG)
|
||||||
|
.valueSerializer(Serializer.BYTE_ARRAY)
|
||||||
|
.makeOrGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void offerFirst(byte[] e) {
|
||||||
|
if(map.isEmpty()) {
|
||||||
|
offerEmpty(e);
|
||||||
|
} else {
|
||||||
|
map.put(map.firstKey() - 1, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized byte[] peekFirst() {
|
||||||
|
if(map.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return map.firstEntry().getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized byte[] pollFirst() {
|
||||||
|
if(map.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return map.pollFirstEntry().getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void offerLast(byte[] e) {
|
||||||
|
if(map.isEmpty()) {
|
||||||
|
offerEmpty(e);
|
||||||
|
} else {
|
||||||
|
map.put(map.lastKey() + 1, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized byte[] peekLast() {
|
||||||
|
if(map.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return map.lastEntry().getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized byte[] pollLast() {
|
||||||
|
if(map.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return map.pollLastEntry().getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return map.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void offerEmpty(byte[] e) {
|
||||||
|
map.put(0L, e);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
package org.ethereum.db;
|
||||||
|
|
||||||
|
import org.ethereum.datasource.QueueDataSource;
|
||||||
|
import org.ethereum.datasource.mapdb.MapDBQueueDataSource;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mikhail Kalinin
|
||||||
|
* @since 07.07.2015
|
||||||
|
*/
|
||||||
|
public class HashStore {
|
||||||
|
|
||||||
|
private static final String DEFAULT_NAME = "hashstore";
|
||||||
|
|
||||||
|
private QueueDataSource hashes;
|
||||||
|
|
||||||
|
private HashStore() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(byte[] hash) {
|
||||||
|
hashes.offerLast(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] peek() {
|
||||||
|
return hashes.peekFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] poll() {
|
||||||
|
return hashes.pollFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFirst(byte[] hash) {
|
||||||
|
hashes.offerFirst(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return hashes.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
hashes.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Builder {
|
||||||
|
private String name = DEFAULT_NAME;
|
||||||
|
private Class<? extends QueueDataSource> dataSourceClass = MapDBQueueDataSource.class;
|
||||||
|
|
||||||
|
public Builder withDataSource(Class<? extends QueueDataSource> dataSourceClass) {
|
||||||
|
this.dataSourceClass = dataSourceClass;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashStore build() throws IllegalAccessException, InstantiationException {
|
||||||
|
HashStore store = new HashStore();
|
||||||
|
store.hashes = dataSourceClass.newInstance();
|
||||||
|
store.hashes.setName(name);
|
||||||
|
store.hashes.init();
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,275 @@
|
||||||
|
package org.ethereum.db;
|
||||||
|
|
||||||
|
import org.ethereum.core.Block;
|
||||||
|
import org.ethereum.datasource.KeyValueDataSource;
|
||||||
|
import org.mapdb.DataIO;
|
||||||
|
import org.mapdb.Serializer;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class IndexedBlockStore {
|
||||||
|
|
||||||
|
IndexedBlockStore cache;
|
||||||
|
Map<Long, List<BlockInfo>> index;
|
||||||
|
KeyValueDataSource blocks;
|
||||||
|
|
||||||
|
public IndexedBlockStore(){
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(Map<Long, List<BlockInfo>> index, KeyValueDataSource blocks, IndexedBlockStore cache) {
|
||||||
|
this.cache = cache;
|
||||||
|
this.index = index;
|
||||||
|
this.blocks = blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush(){
|
||||||
|
|
||||||
|
for (byte[] hash : cache.blocks.keys()){
|
||||||
|
blocks.put(hash, cache.blocks.get(hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
index.putAll( cache.index );
|
||||||
|
|
||||||
|
cache.blocks.close();
|
||||||
|
cache.index.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void addBlock(Block block, BigInteger cummDifficulty, boolean mainChain){
|
||||||
|
if (cache == null)
|
||||||
|
addInternalBlock(block, cummDifficulty, mainChain);
|
||||||
|
else
|
||||||
|
cache.addBlock(block, cummDifficulty, mainChain);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addInternalBlock(Block block, BigInteger cummDifficulty, boolean mainChain){
|
||||||
|
|
||||||
|
List<BlockInfo> blockInfos = index.get(block.getNumber());
|
||||||
|
if (blockInfos == null){
|
||||||
|
blockInfos = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockInfo blockInfo = new BlockInfo();
|
||||||
|
blockInfo.setCummDifficulty(cummDifficulty);
|
||||||
|
blockInfo.setHash(block.getHash());
|
||||||
|
blockInfo.setMainChain(mainChain); // FIXME:maybe here I should force reset main chain for all uncles on that level
|
||||||
|
|
||||||
|
blockInfos.add(blockInfo);
|
||||||
|
index.put(block.getNumber(), blockInfos);
|
||||||
|
|
||||||
|
blocks.put(block.getHash(), block.getEncoded());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Block> getBlocksByNumber(long number){
|
||||||
|
|
||||||
|
List<Block> result = new ArrayList<>();
|
||||||
|
if (cache != null)
|
||||||
|
result = cache.getBlocksByNumber(number);
|
||||||
|
|
||||||
|
List<BlockInfo> blockInfos = index.get(number);
|
||||||
|
if (blockInfos == null){
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BlockInfo blockInfo : blockInfos){
|
||||||
|
|
||||||
|
byte[] hash = blockInfo.getHash();
|
||||||
|
byte[] blockRlp = blocks.get(hash);
|
||||||
|
|
||||||
|
result.add(new Block(blockRlp));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block getChainBlockByNumber(long number){
|
||||||
|
|
||||||
|
if (cache != null) {
|
||||||
|
Block block = cache.getChainBlockByNumber(number);
|
||||||
|
if (block != null) return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BlockInfo> blockInfos = index.get(number);
|
||||||
|
if (blockInfos == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BlockInfo blockInfo : blockInfos){
|
||||||
|
|
||||||
|
if (blockInfo.isMainChain()){
|
||||||
|
|
||||||
|
byte[] hash = blockInfo.getHash();
|
||||||
|
byte[] blockRlp = blocks.get(hash);
|
||||||
|
return new Block(blockRlp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block getBlockByHash(byte[] hash) {
|
||||||
|
|
||||||
|
if (cache != null) {
|
||||||
|
Block cachedBlock = cache.getBlockByHash(hash);
|
||||||
|
if (cachedBlock != null) return cachedBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] blockRlp = blocks.get(hash);
|
||||||
|
if (blockRlp == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new Block(blockRlp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getTotalDifficulty(){
|
||||||
|
|
||||||
|
BigInteger cacheTotalDifficulty = BigInteger.ZERO;
|
||||||
|
|
||||||
|
long maxNumber = getMaxNumber();
|
||||||
|
if (cache != null) {
|
||||||
|
List<BlockInfo> infos = cache.index.get(maxNumber);
|
||||||
|
if (infos != null){
|
||||||
|
for (BlockInfo blockInfo : infos){
|
||||||
|
if (blockInfo.isMainChain()){
|
||||||
|
return blockInfo.getCummDifficulty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BlockInfo> blockInfos = index.get(maxNumber);
|
||||||
|
for (BlockInfo blockInfo : blockInfos){
|
||||||
|
if (blockInfo.isMainChain()){
|
||||||
|
return blockInfo.getCummDifficulty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cacheTotalDifficulty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMaxNumber(){
|
||||||
|
|
||||||
|
Long bestIndex = 0L;
|
||||||
|
|
||||||
|
if (index.size() > 0){
|
||||||
|
bestIndex = (long) index.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cache != null){
|
||||||
|
return bestIndex + cache.index.size() - 1L;
|
||||||
|
} else
|
||||||
|
return bestIndex - 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<byte[]> getNHashesEndWith(byte[] hash, long number){
|
||||||
|
|
||||||
|
List<byte[]> cachedHashes = new ArrayList<>();
|
||||||
|
if (cache != null)
|
||||||
|
cachedHashes = cache.getNHashesEndWith(hash, number);
|
||||||
|
|
||||||
|
byte[] rlp = blocks.get(hash);
|
||||||
|
if (rlp == null) return cachedHashes;
|
||||||
|
|
||||||
|
for (int i = 0; i < number; ++i){
|
||||||
|
|
||||||
|
Block block = new Block(rlp);
|
||||||
|
cachedHashes.add(block.getHash());
|
||||||
|
rlp = blocks.get(block.getParentHash());
|
||||||
|
if (rlp == null) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedHashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<byte[]> getNHashesStartWith(long number, long maxBlocks){
|
||||||
|
|
||||||
|
|
||||||
|
List<byte[]> result = new ArrayList<>();
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for ( i = 0; i < maxBlocks; ++i){
|
||||||
|
List<BlockInfo> blockInfos = index.get(number);
|
||||||
|
if (blockInfos == null) break;
|
||||||
|
|
||||||
|
for (BlockInfo blockInfo : blockInfos)
|
||||||
|
if (blockInfo.isMainChain()){
|
||||||
|
result.add(blockInfo.getHash());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++number;
|
||||||
|
}
|
||||||
|
maxBlocks -= i;
|
||||||
|
|
||||||
|
if (cache != null)
|
||||||
|
result.addAll( cache.getNHashesStartWith(number, maxBlocks) );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BlockInfo implements Serializable {
|
||||||
|
byte[] hash;
|
||||||
|
BigInteger cummDifficulty;
|
||||||
|
boolean mainChain;
|
||||||
|
|
||||||
|
public byte[] getHash() {
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHash(byte[] hash) {
|
||||||
|
this.hash = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getCummDifficulty() {
|
||||||
|
return cummDifficulty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCummDifficulty(BigInteger cummDifficulty) {
|
||||||
|
this.cummDifficulty = cummDifficulty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMainChain() {
|
||||||
|
return mainChain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMainChain(boolean mainChain) {
|
||||||
|
this.mainChain = mainChain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static final Serializer<List<BlockInfo>> BLOCK_INFO_SERIALIZER = new Serializer<List<BlockInfo>>(){
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(DataOutput out, List<BlockInfo> value) throws IOException {
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
ObjectOutputStream oos = new ObjectOutputStream(bos);
|
||||||
|
oos.writeObject(value);
|
||||||
|
|
||||||
|
byte[] data = bos.toByteArray();
|
||||||
|
DataIO.packInt(out, data.length);
|
||||||
|
out.write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BlockInfo> deserialize(DataInput in, int available) throws IOException {
|
||||||
|
|
||||||
|
List<BlockInfo> value = null;
|
||||||
|
try {
|
||||||
|
int size = DataIO.unpackInt(in);
|
||||||
|
byte[] data = new byte[size];
|
||||||
|
in.readFully(data);
|
||||||
|
|
||||||
|
ByteArrayInputStream bis = new ByteArrayInputStream(data, 0, data.length);
|
||||||
|
ObjectInputStream ois = new ObjectInputStream(bis);
|
||||||
|
value = (List<BlockInfo>)ois.readObject();
|
||||||
|
|
||||||
|
} catch (ClassNotFoundException e) {e.printStackTrace();}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package org.ethereum.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class FileUtil {
|
||||||
|
|
||||||
|
public static boolean recursiveDelete(String fileName) {
|
||||||
|
File file = new File(fileName);
|
||||||
|
if (file.exists()) {
|
||||||
|
//check if the file is a directory
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
if ((file.list()).length > 0) {
|
||||||
|
for(String s:file.list()){
|
||||||
|
//call deletion of file individually
|
||||||
|
recursiveDelete(fileName + System.getProperty("file.separator") + s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.setWritable(true);
|
||||||
|
boolean result = file.delete();
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
package org.ethereum.db;
|
||||||
|
|
||||||
|
import org.ethereum.config.SystemProperties;
|
||||||
|
import org.ethereum.util.FileUtil;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Mikhail Kalinin
|
||||||
|
* @since 07.07.2015
|
||||||
|
*/
|
||||||
|
public class HashStoreTest {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger("test");
|
||||||
|
|
||||||
|
private List<byte[]> hashes = new ArrayList<>();
|
||||||
|
private HashStore hashStore;
|
||||||
|
private String testDb;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws InstantiationException, IllegalAccessException {
|
||||||
|
Random rnd = new Random(System.currentTimeMillis());
|
||||||
|
for(int i = 0; i < 50; i++) {
|
||||||
|
byte[] hash = new byte[32];
|
||||||
|
rnd.nextBytes(hash);
|
||||||
|
hashes.add(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger bi = new BigInteger(32, new Random());
|
||||||
|
testDb = "test_db_" + bi;
|
||||||
|
SystemProperties.CONFIG.setDataBaseDir(testDb);
|
||||||
|
hashStore = new HashStore.Builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanup() {
|
||||||
|
hashStore.close();
|
||||||
|
FileUtil.recursiveDelete(testDb);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // FIFO, add first
|
||||||
|
public void test1() throws InstantiationException, IllegalAccessException {
|
||||||
|
for(byte[] hash : hashes) {
|
||||||
|
hashStore.add(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing peek and poll
|
||||||
|
assertArrayEquals(hashes.get(0), hashStore.peek());
|
||||||
|
for(byte[] hash : hashes) {
|
||||||
|
assertArrayEquals(hash, hashStore.poll());
|
||||||
|
}
|
||||||
|
assertEquals(true, hashStore.isEmpty());
|
||||||
|
assertNull(hashStore.peek());
|
||||||
|
assertNull(hashStore.poll());
|
||||||
|
|
||||||
|
// testing addFirst
|
||||||
|
for(int i = 0; i < 10; i++) {
|
||||||
|
hashStore.add(hashes.get(i));
|
||||||
|
}
|
||||||
|
for(int i = 10; i < 20; i++) {
|
||||||
|
hashStore.addFirst(hashes.get(i));
|
||||||
|
}
|
||||||
|
for(int i = 19; i >= 10; i--) {
|
||||||
|
assertArrayEquals(hashes.get(i), hashStore.poll());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // concurrency
|
||||||
|
public void test2() throws InstantiationException, IllegalAccessException, InterruptedException {
|
||||||
|
new Thread(new Writer(1)).start();
|
||||||
|
new Thread(new Writer(2)).start();
|
||||||
|
new Thread(new Writer(3)).start();
|
||||||
|
new Thread(new Reader(1)).start();
|
||||||
|
Thread r2 = new Thread(new Reader(2));
|
||||||
|
r2.start();
|
||||||
|
r2.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Reader implements Runnable {
|
||||||
|
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
public Reader(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
int nullsCount = 0;
|
||||||
|
while (nullsCount < 5) {
|
||||||
|
byte[] hash = hashStore.poll();
|
||||||
|
logger.info("reader {}: {}", index, hash == null ? null : Hex.toHexString(hash));
|
||||||
|
if(hash == null) {
|
||||||
|
nullsCount++;
|
||||||
|
} else {
|
||||||
|
nullsCount = 0;
|
||||||
|
}
|
||||||
|
Thread.sleep(50);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Writer implements Runnable {
|
||||||
|
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
public Writer(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
for(byte[] hash : hashes) {
|
||||||
|
hashStore.add(hash);
|
||||||
|
logger.info("writer {}: {}", index, Hex.toHexString(hash));
|
||||||
|
Thread.sleep(50);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,709 @@
|
||||||
|
package org.ethereum.db;
|
||||||
|
|
||||||
|
import org.ethereum.config.SystemProperties;
|
||||||
|
import org.ethereum.core.Block;
|
||||||
|
import org.ethereum.core.Genesis;
|
||||||
|
import org.ethereum.datasource.HashMapDB;
|
||||||
|
import org.ethereum.datasource.KeyValueDataSource;
|
||||||
|
import org.ethereum.datasource.LevelDbDataSource;
|
||||||
|
import org.ethereum.util.FileUtil;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mapdb.DB;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static java.math.BigInteger.ZERO;
|
||||||
|
import static org.ethereum.TestUtils.createIndexMap;
|
||||||
|
import static org.ethereum.TestUtils.createMapDB;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
|
||||||
|
public class IndexedBlockStoreTest {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger("test");
|
||||||
|
private List<Block> blocks = new ArrayList<>();
|
||||||
|
private BigInteger cumDifficulty = ZERO;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws URISyntaxException, IOException {
|
||||||
|
|
||||||
|
URL scenario1 = ClassLoader
|
||||||
|
.getSystemResource("blockstore/load.dmp");
|
||||||
|
|
||||||
|
File file = new File(scenario1.toURI());
|
||||||
|
List<String> strData = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
Block genesis = Genesis.getInstance();
|
||||||
|
blocks.add(genesis);
|
||||||
|
cumDifficulty = cumDifficulty.add(genesis.getCumulativeDifficulty());
|
||||||
|
|
||||||
|
for (String blockRLP : strData) {
|
||||||
|
|
||||||
|
Block block = new Block(
|
||||||
|
Hex.decode(blockRLP));
|
||||||
|
|
||||||
|
if (block.getNumber() % 1000 == 0)
|
||||||
|
logger.info("adding block.hash: [{}] block.number: [{}]",
|
||||||
|
block.getShortHash(),
|
||||||
|
block.getNumber());
|
||||||
|
|
||||||
|
blocks.add(block);
|
||||||
|
cumDifficulty = cumDifficulty.add(block.getCumulativeDifficulty());
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("total difficulty: {}", cumDifficulty);
|
||||||
|
logger.info("total blocks loaded: {}", blocks.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test // no cache, save some load, and check it exist
|
||||||
|
public void test1(){
|
||||||
|
|
||||||
|
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
|
||||||
|
indexedBlockStore.init(new HashMap<Long, List<IndexedBlockStore.BlockInfo>>(), new HashMapDB(), null);
|
||||||
|
|
||||||
|
BigInteger cummDiff = BigInteger.ZERO;
|
||||||
|
for (Block block : blocks){
|
||||||
|
cummDiff = cummDiff.add( block.getCumulativeDifficulty() );
|
||||||
|
indexedBlockStore.addBlock(block, cummDiff, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing: getTotalDifficulty()
|
||||||
|
// testing: getMaxNumber()
|
||||||
|
|
||||||
|
long bestIndex = blocks.get(blocks.size() - 1).getNumber();
|
||||||
|
assertEquals(bestIndex, indexedBlockStore.getMaxNumber());
|
||||||
|
assertEquals(cumDifficulty, indexedBlockStore.getTotalDifficulty());
|
||||||
|
|
||||||
|
// testing: getBlockByHash(byte[])
|
||||||
|
|
||||||
|
Block block = blocks.get(50);
|
||||||
|
Block block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(Hex.decode("00112233"));
|
||||||
|
assertEquals(null, block_);
|
||||||
|
|
||||||
|
// testing: getChainBlockByNumber(long)
|
||||||
|
|
||||||
|
block = blocks.get(50);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(10000);
|
||||||
|
assertEquals(null, block_);
|
||||||
|
|
||||||
|
// testing: getBlocksByNumber(long)
|
||||||
|
|
||||||
|
block = blocks.get(50);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
int blocksNum = indexedBlockStore.getBlocksByNumber(10000).size();
|
||||||
|
assertEquals(0, blocksNum);
|
||||||
|
|
||||||
|
// testing: getNHashesEndWith(byte[], long)
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
List<byte[]> hashList = indexedBlockStore.getNHashesEndWith(block.getHash(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(8003 - i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing: getNHashesStartWith(long, long)
|
||||||
|
|
||||||
|
block = blocks.get(7003);
|
||||||
|
hashList = indexedBlockStore.getNHashesStartWith(block.getNumber(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(7003 + i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // predefined cache, save some load, and check it exist
|
||||||
|
public void test2(){
|
||||||
|
|
||||||
|
IndexedBlockStore cache = new IndexedBlockStore();
|
||||||
|
cache.init(new HashMap<Long, List<IndexedBlockStore.BlockInfo>>(), new HashMapDB(), null);
|
||||||
|
|
||||||
|
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
|
||||||
|
indexedBlockStore.init(new HashMap<Long, List<IndexedBlockStore.BlockInfo>>(), new HashMapDB(), cache);
|
||||||
|
|
||||||
|
BigInteger cummDiff = BigInteger.ZERO;
|
||||||
|
for (Block block : blocks){
|
||||||
|
cummDiff = cummDiff.add( block.getCumulativeDifficulty() );
|
||||||
|
indexedBlockStore.addBlock(block, cummDiff, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing: getTotalDifficulty()
|
||||||
|
// testing: getMaxNumber()
|
||||||
|
|
||||||
|
long bestIndex = blocks.get(blocks.size() - 1).getNumber();
|
||||||
|
assertEquals(bestIndex, indexedBlockStore.getMaxNumber());
|
||||||
|
assertEquals(cumDifficulty, indexedBlockStore.getTotalDifficulty());
|
||||||
|
|
||||||
|
// testing: getBlockByHash(byte[])
|
||||||
|
|
||||||
|
Block block = blocks.get(50);
|
||||||
|
Block block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(Hex.decode("00112233"));
|
||||||
|
assertEquals(null, block_);
|
||||||
|
|
||||||
|
// testing: getChainBlockByNumber(long)
|
||||||
|
|
||||||
|
block = blocks.get(50);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(10000);
|
||||||
|
assertEquals(null, block_);
|
||||||
|
|
||||||
|
// testing: getBlocksByNumber(long)
|
||||||
|
|
||||||
|
block = blocks.get(50);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
int blocksNum = indexedBlockStore.getBlocksByNumber(10000).size();
|
||||||
|
assertEquals(0, blocksNum);
|
||||||
|
|
||||||
|
// testing: getNHashesEndWith(byte[], long)
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
List<byte[]> hashList = indexedBlockStore.getNHashesEndWith(block.getHash(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(8003 - i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing: getNHashesStartWith(long, long)
|
||||||
|
|
||||||
|
block = blocks.get(7003);
|
||||||
|
hashList = indexedBlockStore.getNHashesStartWith(block.getNumber(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(7003 + i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // predefined cache loaded and flushed, check it exist
|
||||||
|
public void test3(){
|
||||||
|
|
||||||
|
IndexedBlockStore cache = new IndexedBlockStore();
|
||||||
|
cache.init(new HashMap<Long, List<IndexedBlockStore.BlockInfo>>(), new HashMapDB(), null);
|
||||||
|
|
||||||
|
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
|
||||||
|
indexedBlockStore.init(new HashMap<Long, List<IndexedBlockStore.BlockInfo>>(), new HashMapDB(), cache);
|
||||||
|
|
||||||
|
BigInteger cummDiff = BigInteger.ZERO;
|
||||||
|
for (Block block : blocks){
|
||||||
|
cummDiff = cummDiff.add( block.getCumulativeDifficulty() );
|
||||||
|
indexedBlockStore.addBlock(block, cummDiff, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
indexedBlockStore.flush();
|
||||||
|
|
||||||
|
// testing: getTotalDifficulty()
|
||||||
|
// testing: getMaxNumber()
|
||||||
|
|
||||||
|
long bestIndex = blocks.get(blocks.size() - 1).getNumber();
|
||||||
|
assertEquals(bestIndex, indexedBlockStore.getMaxNumber());
|
||||||
|
assertEquals(cumDifficulty, indexedBlockStore.getTotalDifficulty());
|
||||||
|
|
||||||
|
// testing: getBlockByHash(byte[])
|
||||||
|
|
||||||
|
Block block = blocks.get(50);
|
||||||
|
Block block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(Hex.decode("00112233"));
|
||||||
|
assertEquals(null, block_);
|
||||||
|
|
||||||
|
// testing: getChainBlockByNumber(long)
|
||||||
|
|
||||||
|
block = blocks.get(50);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(10000);
|
||||||
|
assertEquals(null, block_);
|
||||||
|
|
||||||
|
// testing: getBlocksByNumber(long)
|
||||||
|
|
||||||
|
block = blocks.get(50);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
int blocksNum = indexedBlockStore.getBlocksByNumber(10000).size();
|
||||||
|
assertEquals(0, blocksNum);
|
||||||
|
|
||||||
|
// testing: getNHashesEndWith(byte[], long)
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
List<byte[]> hashList = indexedBlockStore.getNHashesEndWith(block.getHash(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(8003 - i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing: getNHashesStartWith(long, long)
|
||||||
|
|
||||||
|
block = blocks.get(7003);
|
||||||
|
hashList = indexedBlockStore.getNHashesStartWith(block.getNumber(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(7003 + i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test // cache + leveldb + mapdb, save some load, flush to disk, and check it exist
|
||||||
|
public void test4() throws IOException {
|
||||||
|
|
||||||
|
BigInteger bi = new BigInteger(32, new Random());
|
||||||
|
String testDir = "test_db_" + bi;
|
||||||
|
SystemProperties.CONFIG.setDataBaseDir(testDir);
|
||||||
|
|
||||||
|
DB db = createMapDB(testDir);
|
||||||
|
Map<Long, List<IndexedBlockStore.BlockInfo>> indexDB = createIndexMap(db);
|
||||||
|
|
||||||
|
KeyValueDataSource blocksDB = new LevelDbDataSource("blocks");
|
||||||
|
blocksDB.init();
|
||||||
|
|
||||||
|
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
|
||||||
|
indexedBlockStore.init(indexDB, blocksDB, null);
|
||||||
|
|
||||||
|
|
||||||
|
BigInteger cummDiff = BigInteger.ZERO;
|
||||||
|
for (Block block : blocks){
|
||||||
|
cummDiff = cummDiff.add( block.getCumulativeDifficulty() );
|
||||||
|
indexedBlockStore.addBlock(block, cummDiff, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing: getTotalDifficulty()
|
||||||
|
// testing: getMaxNumber()
|
||||||
|
|
||||||
|
long bestIndex = blocks.get(blocks.size() - 1).getNumber();
|
||||||
|
assertEquals(bestIndex, indexedBlockStore.getMaxNumber());
|
||||||
|
assertEquals(cumDifficulty, indexedBlockStore.getTotalDifficulty());
|
||||||
|
|
||||||
|
// testing: getBlockByHash(byte[])
|
||||||
|
|
||||||
|
Block block = blocks.get(50);
|
||||||
|
Block block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(Hex.decode("00112233"));
|
||||||
|
assertEquals(null, block_);
|
||||||
|
|
||||||
|
// testing: getChainBlockByNumber(long)
|
||||||
|
|
||||||
|
block = blocks.get(50);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(10000);
|
||||||
|
assertEquals(null, block_);
|
||||||
|
|
||||||
|
// testing: getBlocksByNumber(long)
|
||||||
|
|
||||||
|
block = blocks.get(50);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
int blocksNum = indexedBlockStore.getBlocksByNumber(10000).size();
|
||||||
|
assertEquals(0, blocksNum);
|
||||||
|
|
||||||
|
// testing: getNHashesEndWith(byte[], long)
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
List<byte[]> hashList = indexedBlockStore.getNHashesEndWith(block.getHash(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(8003 - i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing: getNHashesStartWith(long, long)
|
||||||
|
|
||||||
|
block = blocks.get(7003);
|
||||||
|
hashList = indexedBlockStore.getNHashesStartWith(block.getNumber(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(7003 + i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
blocksDB.close();
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
// testing after: REOPEN
|
||||||
|
|
||||||
|
db = createMapDB(testDir);
|
||||||
|
indexDB = createIndexMap(db);
|
||||||
|
|
||||||
|
blocksDB = new LevelDbDataSource("blocks");
|
||||||
|
blocksDB.init();
|
||||||
|
|
||||||
|
indexedBlockStore = new IndexedBlockStore();
|
||||||
|
indexedBlockStore.init(indexDB, blocksDB, null);
|
||||||
|
|
||||||
|
// testing: getNHashesStartWith(long, long)
|
||||||
|
|
||||||
|
block = blocks.get(7003);
|
||||||
|
hashList = indexedBlockStore.getNHashesStartWith(block.getNumber(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(7003 + i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileUtil.recursiveDelete(testDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // cache + leveldb + mapdb, save part to disk part to cache, and check it exist
|
||||||
|
public void test5() throws IOException {
|
||||||
|
|
||||||
|
BigInteger bi = new BigInteger(32, new Random());
|
||||||
|
String testDir = "test_db_" + bi;
|
||||||
|
SystemProperties.CONFIG.setDataBaseDir(testDir);
|
||||||
|
|
||||||
|
DB db = createMapDB(testDir);
|
||||||
|
Map<Long, List<IndexedBlockStore.BlockInfo>> indexDB = createIndexMap(db);
|
||||||
|
|
||||||
|
KeyValueDataSource blocksDB = new LevelDbDataSource("blocks");
|
||||||
|
blocksDB.init();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
IndexedBlockStore cache = new IndexedBlockStore();
|
||||||
|
cache.init(new HashMap<Long, List<IndexedBlockStore.BlockInfo>>(), new HashMapDB(), null);
|
||||||
|
|
||||||
|
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
|
||||||
|
indexedBlockStore.init(indexDB, blocksDB, cache);
|
||||||
|
|
||||||
|
|
||||||
|
BigInteger cummDiff = BigInteger.ZERO;
|
||||||
|
int preloadSize = blocks.size() / 2;
|
||||||
|
for (int i = 0; i < preloadSize; ++i){
|
||||||
|
Block block = blocks.get(i);
|
||||||
|
cummDiff = cummDiff.add( block.getCumulativeDifficulty() );
|
||||||
|
indexedBlockStore.addBlock(block, cummDiff, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
indexedBlockStore.flush();
|
||||||
|
|
||||||
|
for (int i = preloadSize; i < blocks.size(); ++i){
|
||||||
|
Block block = blocks.get(i);
|
||||||
|
cummDiff = cummDiff.add( block.getCumulativeDifficulty() );
|
||||||
|
indexedBlockStore.addBlock(block, cummDiff, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing: getTotalDifficulty()
|
||||||
|
// testing: getMaxNumber()
|
||||||
|
|
||||||
|
long bestIndex = blocks.get(blocks.size() - 1).getNumber();
|
||||||
|
assertEquals(bestIndex, indexedBlockStore.getMaxNumber());
|
||||||
|
assertEquals(cumDifficulty, indexedBlockStore.getTotalDifficulty());
|
||||||
|
|
||||||
|
// testing: getBlockByHash(byte[])
|
||||||
|
|
||||||
|
Block block = blocks.get(50);
|
||||||
|
Block block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(block.getHash());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block_ = indexedBlockStore.getBlockByHash(Hex.decode("00112233"));
|
||||||
|
assertEquals(null, block_);
|
||||||
|
|
||||||
|
// testing: getChainBlockByNumber(long)
|
||||||
|
|
||||||
|
block = blocks.get(50);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(block.getNumber());
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block_ = indexedBlockStore.getChainBlockByNumber(10000);
|
||||||
|
assertEquals(null, block_);
|
||||||
|
|
||||||
|
// testing: getBlocksByNumber(long)
|
||||||
|
|
||||||
|
block = blocks.get(50);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(150);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(0);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
block_ = indexedBlockStore.getBlocksByNumber(block.getNumber()).get(0);
|
||||||
|
assertEquals(block.getNumber(), block_.getNumber());
|
||||||
|
|
||||||
|
int blocksNum = indexedBlockStore.getBlocksByNumber(10000).size();
|
||||||
|
assertEquals(0, blocksNum);
|
||||||
|
|
||||||
|
// testing: getNHashesEndWith(byte[], long)
|
||||||
|
|
||||||
|
block = blocks.get(8003);
|
||||||
|
List<byte[]> hashList = indexedBlockStore.getNHashesEndWith(block.getHash(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(8003 - i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing: getNHashesStartWith(long, long)
|
||||||
|
|
||||||
|
block = blocks.get(7003);
|
||||||
|
hashList = indexedBlockStore.getNHashesStartWith(block.getNumber(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(7003 + i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
indexedBlockStore.flush();
|
||||||
|
blocksDB.close();
|
||||||
|
db.close();
|
||||||
|
|
||||||
|
// testing after: REOPEN
|
||||||
|
|
||||||
|
db = createMapDB(testDir);
|
||||||
|
indexDB = createIndexMap(db);
|
||||||
|
|
||||||
|
blocksDB = new LevelDbDataSource("blocks");
|
||||||
|
blocksDB.init();
|
||||||
|
|
||||||
|
indexedBlockStore = new IndexedBlockStore();
|
||||||
|
indexedBlockStore.init(indexDB, blocksDB, null);
|
||||||
|
|
||||||
|
|
||||||
|
// testing: getNHashesStartWith(long, long)
|
||||||
|
|
||||||
|
block = blocks.get(7003);
|
||||||
|
hashList = indexedBlockStore.getNHashesStartWith(block.getNumber(), 100);
|
||||||
|
for (int i = 0; i < 100; ++i){
|
||||||
|
block = blocks.get(7003 + i);
|
||||||
|
String hash = Hex.toHexString(hashList.get(i));
|
||||||
|
String hash_ = Hex.toHexString( block.getHash() );
|
||||||
|
assertEquals(hash_, hash);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
blocksDB.close();
|
||||||
|
db.close();
|
||||||
|
FileUtil.recursiveDelete(testDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue