/*
* Copyright (c) [2016] [ <ether.camp> ]
* This file is part of the ethereumJ library.
*
* The ethereumJ library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The ethereumJ library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>.
*/
package org.ethereum.db;
import org.ethereum.config.SystemProperties;
import org.ethereum.config.blockchain.FrontierConfig;
import org.ethereum.config.net.MainNetConfig;
import org.ethereum.core.Block;
import org.ethereum.core.Genesis;
import org.ethereum.datasource.DbSource;
import org.ethereum.datasource.leveldb.LevelDbDataSource;
import org.ethereum.datasource.inmem.HashMapDB;
import org.ethereum.util.FileUtil;
import org.ethereum.util.blockchain.StandaloneBlockchain;
import org.junit.*;
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.*;
import static org.ethereum.util.ByteUtil.wrap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class IndexedBlockStoreTest {
private static final Logger logger = LoggerFactory.getLogger("test");
private List<Block> blocks = new ArrayList<>();
private BigInteger cumDifficulty = ZERO;
@AfterClass
public static void cleanup() {
SystemProperties.resetToDefault();
}
@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 HashMapDB<byte[]>(), new HashMapDB<byte[]>());
BigInteger cummDiff = BigInteger.ZERO;
for (Block block : blocks){
cummDiff = cummDiff.add( block.getCumulativeDifficulty() );
indexedBlockStore.saveBlock(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: getListHashesEndWith(byte[], long)
block = blocks.get(8003);
List<byte[]> hashList = indexedBlockStore.getListHashesEndWith(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: getListHashesStartWith(long, long)
block = blocks.get(7003);
hashList = indexedBlockStore.getListHashesStartWith(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 HashMapDB<byte[]>(), new HashMapDB<byte[]>());
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
indexedBlockStore.init(new HashMapDB<byte[]>(), new HashMapDB<byte[]>());
BigInteger cummDiff = BigInteger.ZERO;
for (Block block : blocks){
cummDiff = cummDiff.add( block.getCumulativeDifficulty() );
indexedBlockStore.saveBlock(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: getListHashesEndWith(byte[], long)
block = blocks.get(8003);
List<byte[]> hashList = indexedBlockStore.getListHashesEndWith(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: getListHashesStartWith(long, long)
block = blocks.get(7003);
hashList = indexedBlockStore.getListHashesStartWith(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 HashMapDB<byte[]>(), new HashMapDB<byte[]>());
// TODO cache removed, remove this test?
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
indexedBlockStore.init(new HashMapDB<byte[]>(), new HashMapDB<byte[]>());
BigInteger cummDiff = BigInteger.ZERO;
for (Block block : blocks){
cummDiff = cummDiff.add( block.getCumulativeDifficulty() );
indexedBlockStore.saveBlock(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: getListHashesEndWith(byte[], long)
block = blocks.get(8003);
List<byte[]> hashList = indexedBlockStore.getListHashesEndWith(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: getListHashesStartWith(long, long)
block = blocks.get(7003);
hashList = indexedBlockStore.getListHashesStartWith(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.getDefault().setDataBaseDir(testDir);
LevelDbDataSource indexDB = new LevelDbDataSource("index");
indexDB.init();
DbSource blocksDB = new LevelDbDataSource("blocks");
blocksDB.init();
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
indexedBlockStore.init(indexDB, blocksDB);
BigInteger cummDiff = BigInteger.ZERO;
for (Block block : blocks){
cummDiff = cummDiff.add( block.getCumulativeDifficulty() );
indexedBlockStore.saveBlock(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: getListHashesEndWith(byte[], long)
block = blocks.get(8003);
List<byte[]> hashList = indexedBlockStore.getListHashesEndWith(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: getListHashesStartWith(long, long)
block = blocks.get(7003);
hashList = indexedBlockStore.getListHashesStartWith(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();
indexDB.close();
// testing after: REOPEN
indexDB = new LevelDbDataSource("index");
indexDB.init();
blocksDB = new LevelDbDataSource("blocks");
blocksDB.init();
indexedBlockStore = new IndexedBlockStore();
indexedBlockStore.init(indexDB, blocksDB);
// testing: getListHashesStartWith(long, long)
block = blocks.get(7003);
hashList = indexedBlockStore.getListHashesStartWith(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();
indexDB.close();
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.getDefault().setDataBaseDir(testDir);
LevelDbDataSource indexDB = new LevelDbDataSource("index");
indexDB.init();
DbSource blocksDB = new LevelDbDataSource("blocks");
blocksDB.init();
try {
IndexedBlockStore cache = new IndexedBlockStore();
cache.init(new HashMapDB<byte[]>(), new HashMapDB<byte[]>());
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
indexedBlockStore.init(indexDB, blocksDB);
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.saveBlock(block, cummDiff, true);
}
indexedBlockStore.flush();
for (int i = preloadSize; i < blocks.size(); ++i){
Block block = blocks.get(i);
cummDiff = cummDiff.add( block.getCumulativeDifficulty() );
indexedBlockStore.saveBlock(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: getListHashesEndWith(byte[], long)
block = blocks.get(8003);
List<byte[]> hashList = indexedBlockStore.getListHashesEndWith(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: getListHashesStartWith(long, long)
block = blocks.get(7003);
hashList = indexedBlockStore.getListHashesStartWith(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();
indexDB.close();
// testing after: REOPEN
indexDB = new LevelDbDataSource("index");
indexDB.init();
blocksDB = new LevelDbDataSource("blocks");
blocksDB.init();
indexedBlockStore = new IndexedBlockStore();
indexedBlockStore.init(indexDB, blocksDB);
// testing: getListHashesStartWith(long, long)
block = blocks.get(7003);
hashList = indexedBlockStore.getListHashesStartWith(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();
indexDB.close();
FileUtil.recursiveDelete(testDir);
}
}
@Test // cache + leveldb + mapdb, multi branch, total difficulty test
public void test6() throws IOException {
BigInteger bi = new BigInteger(32, new Random());
String testDir = "test_db_" + bi;
SystemProperties.getDefault().setDataBaseDir(testDir);
DbSource indexDB = new LevelDbDataSource("index");
indexDB.init();
DbSource blocksDB = new LevelDbDataSource("blocks");
blocksDB.init();
try {
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
indexedBlockStore.init(indexDB, blocksDB);
List<Block> bestLine = getRandomChain(Genesis.getInstance().getHash(), 1, 100);
indexedBlockStore.saveBlock(Genesis.getInstance(), Genesis.getInstance().getCumulativeDifficulty(), true);
for (int i = 0; i < bestLine.size(); ++i){
BigInteger td = indexedBlockStore.getTotalDifficulty();
Block newBlock = bestLine.get(i);
td = td.add(newBlock.getCumulativeDifficulty());
indexedBlockStore.saveBlock(newBlock, td, true);
}
byte[] forkParentHash = bestLine.get(60).getHash();
long forkParentNumber = bestLine.get(60).getNumber();
List<Block> forkLine = getRandomChain(forkParentHash, forkParentNumber + 1, 50);
for (int i = 0; i < forkLine.size(); ++i){
Block newBlock = forkLine.get(i);
Block parentBlock = indexedBlockStore.getBlockByHash(newBlock.getParentHash());
BigInteger td = indexedBlockStore.getTotalDifficultyForHash(parentBlock.getHash());
td = td.add(newBlock.getCumulativeDifficulty());
indexedBlockStore.saveBlock(newBlock, td, false);
}
// calc all TDs
Map<ByteArrayWrapper, BigInteger> tDiffs = new HashMap<>();
BigInteger td = Genesis.getInstance().getCumulativeDifficulty();
for (Block block : bestLine){
td = td.add(block.getCumulativeDifficulty());
tDiffs.put(wrap(block.getHash()), td);
}
Map<ByteArrayWrapper, BigInteger> tForkDiffs = new HashMap<>();
Block block = forkLine.get(0);
td = tDiffs.get(wrap(block.getParentHash()));
for (Block currBlock : forkLine){
td = td.add(currBlock.getCumulativeDifficulty());
tForkDiffs.put(wrap(currBlock.getHash()), td);
}
// Assert tds on bestLine
for ( ByteArrayWrapper hash : tDiffs.keySet()){
BigInteger currTD = tDiffs.get(hash);
BigInteger checkTd = indexedBlockStore.getTotalDifficultyForHash(hash.getData());
assertEquals(checkTd, currTD);
}
// Assert tds on forkLine
for ( ByteArrayWrapper hash : tForkDiffs.keySet()){
BigInteger currTD = tForkDiffs.get(hash);
BigInteger checkTd = indexedBlockStore.getTotalDifficultyForHash(hash.getData());
assertEquals(checkTd, currTD);
}
indexedBlockStore.flush();
// Assert tds on bestLine
for ( ByteArrayWrapper hash : tDiffs.keySet()){
BigInteger currTD = tDiffs.get(hash);
BigInteger checkTd = indexedBlockStore.getTotalDifficultyForHash(hash.getData());
assertEquals(checkTd, currTD);
}
// check total difficulty
BigInteger totalDifficulty = indexedBlockStore.getTotalDifficulty();
Block bestBlock = bestLine.get(bestLine.size() - 1);
BigInteger totalDifficulty_ = tDiffs.get(wrap(bestBlock.getHash()));
assertEquals(totalDifficulty_, totalDifficulty);
// Assert tds on forkLine
for ( ByteArrayWrapper hash : tForkDiffs.keySet()){
BigInteger currTD = tForkDiffs.get(hash);
BigInteger checkTd = indexedBlockStore.getTotalDifficultyForHash(hash.getData());
assertEquals(checkTd, currTD);
}
} finally {
blocksDB.close();
indexDB.close();
FileUtil.recursiveDelete(testDir);
}
}
@Test // cache + leveldb + mapdb, multi branch, total re-branch test
public void test7() throws IOException {
BigInteger bi = new BigInteger(32, new Random());
String testDir = "test_db_" + bi;
SystemProperties.getDefault().setDataBaseDir(testDir);
DbSource indexDB = new LevelDbDataSource("index");
indexDB.init();
DbSource blocksDB = new LevelDbDataSource("blocks");
blocksDB.init();
try {
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
indexedBlockStore.init(indexDB, blocksDB);
List<Block> bestLine = getRandomChain(Genesis.getInstance().getHash(), 1, 100);
indexedBlockStore.saveBlock(Genesis.getInstance(), Genesis.getInstance().getCumulativeDifficulty(), true);
for (int i = 0; i < bestLine.size(); ++i){
BigInteger td = indexedBlockStore.getTotalDifficulty();
Block newBlock = bestLine.get(i);
td = td.add(newBlock.getCumulativeDifficulty());
indexedBlockStore.saveBlock(newBlock, td, true);
}
byte[] forkParentHash = bestLine.get(60).getHash();
long forkParentNumber = bestLine.get(60).getNumber();
List<Block> forkLine = getRandomChain(forkParentHash, forkParentNumber + 1, 50);
for (int i = 0; i < forkLine.size(); ++i){
Block newBlock = forkLine.get(i);
Block parentBlock = indexedBlockStore.getBlockByHash(newBlock.getParentHash());
BigInteger td = indexedBlockStore.getTotalDifficultyForHash(parentBlock.getHash());
td = td.add(newBlock.getCumulativeDifficulty());
indexedBlockStore.saveBlock(newBlock, td, false);
}
Block bestBlock = bestLine.get(bestLine.size() - 1);
Block forkBlock = forkLine.get(forkLine.size() - 1);
// check total difficulty
BigInteger totalDifficulty = indexedBlockStore.getTotalDifficulty();
BigInteger totalDifficulty_ = indexedBlockStore.getTotalDifficultyForHash( bestBlock.getHash() );
assertEquals(totalDifficulty_, totalDifficulty);
indexedBlockStore.reBranch(forkBlock);
// check total difficulty
totalDifficulty = indexedBlockStore.getTotalDifficulty();
totalDifficulty_ = indexedBlockStore.getTotalDifficultyForHash( forkBlock.getHash() );
assertEquals(totalDifficulty_, totalDifficulty);
} finally {
blocksDB.close();
indexDB.close();
FileUtil.recursiveDelete(testDir);
}
}
@Test // cache + leveldb + mapdb, multi branch, total re-branch test
public void test8() throws IOException {
BigInteger bi = new BigInteger(32, new Random());
String testDir = "test_db_" + bi;
SystemProperties.getDefault().setDataBaseDir(testDir);
DbSource indexDB = new LevelDbDataSource("index");
indexDB.init();
DbSource blocksDB = new LevelDbDataSource("blocks");
blocksDB.init();
try {
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
indexedBlockStore.init(indexDB, blocksDB);
List<Block> bestLine = getRandomChain(Genesis.getInstance().getHash(), 1, 100);
indexedBlockStore.saveBlock(Genesis.getInstance(), Genesis.getInstance().getCumulativeDifficulty(), true);
for (int i = 0; i < bestLine.size(); ++i){
BigInteger td = indexedBlockStore.getTotalDifficulty();
Block newBlock = bestLine.get(i);
td = td.add(newBlock.getCumulativeDifficulty());
indexedBlockStore.saveBlock(newBlock, td, true);
}
byte[] forkParentHash = bestLine.get(60).getHash();
long forkParentNumber = bestLine.get(60).getNumber();
List<Block> forkLine = getRandomChain(forkParentHash, forkParentNumber + 1, 10);
for (int i = 0; i < forkLine.size(); ++i){
Block newBlock = forkLine.get(i);
Block parentBlock = indexedBlockStore.getBlockByHash(newBlock.getParentHash());
BigInteger td = indexedBlockStore.getTotalDifficultyForHash(parentBlock.getHash());
td = td.add(newBlock.getCumulativeDifficulty());
indexedBlockStore.saveBlock(newBlock, td, false);
}
Block bestBlock = bestLine.get(bestLine.size() - 1);
Block forkBlock = forkLine.get(forkLine.size() - 1);
assertTrue( indexedBlockStore.getBestBlock().getNumber() == 100);
// check total difficulty
BigInteger totalDifficulty = indexedBlockStore.getTotalDifficulty();
BigInteger totalDifficulty_ = indexedBlockStore.getTotalDifficultyForHash(bestBlock.getHash());
assertEquals(totalDifficulty_, totalDifficulty);
indexedBlockStore.reBranch(forkBlock);
assertTrue( indexedBlockStore.getBestBlock().getNumber() == 71);
// check total difficulty
totalDifficulty = indexedBlockStore.getTotalDifficulty();
totalDifficulty_ = indexedBlockStore.getTotalDifficultyForHash( forkBlock.getHash() );
assertEquals(totalDifficulty_, totalDifficulty);
// Assert that all fork moved to the main line
for (Block currBlock : forkLine){
Long number = currBlock.getNumber();
Block chainBlock = indexedBlockStore.getChainBlockByNumber(number);
assertEquals(currBlock.getShortHash(), chainBlock.getShortHash());
}
// Assert that all fork moved to the main line
// re-branch back to previous line and assert that
// all the block really moved
bestBlock = bestLine.get(bestLine.size() - 1);
indexedBlockStore.reBranch(bestBlock);
for (Block currBlock : bestLine){
Long number = currBlock.getNumber();
Block chainBlock = indexedBlockStore.getChainBlockByNumber(number);
assertEquals(currBlock.getShortHash(), chainBlock.getShortHash());
}
} finally {
blocksDB.close();
indexDB.close();
FileUtil.recursiveDelete(testDir);
}
}
@Test // test index merging during the flush
public void test9() {
IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
indexedBlockStore.init(new HashMapDB<byte[]>(), new HashMapDB<byte[]>());
// blocks with the same block number
Block block1 = new Block(Hex.decode("f90202f901fda0ad0d51e8d64c364a7b77ef2fe252f3f4df0940c7cfa69cedc1fbd6ea66894936a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479414a3bc0f103706650a19c5d24e5c4cf1ea5af78ea0e0580f4fdd1e3ae8346efaa6b1018605361f6e2fb058580e31414c8cbf5b0d49a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008605065cf2c43a8303e52e832fefd8808455fcbe1b80a017247341fd5d2f1d384682fea9302065a95dbd3e4f8260dde88a386f3cb95be3880f3fc8d5e0c87378c0c0"));
Block block2 = new Block(Hex.decode("f90218f90213a0c63fc3626abc6f6ba695064e973126cccc6fd513d4f53485e11794a8855e8b2ba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347941dcb8d1f0fcc8cbc8c2d76528e877f915e299fbea0ccb2ed2a8c585409fe5530d36320bc8c1406454b32a9e419e890ea49489e534aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008605079eb238d88303e52e832fefd8808455fcbe2596d583010103844765746885676f312e35856c696e7578a0a673a429161eb32e6d0887b2bce2b12b1edd6e4b4cf55371853cba13d57118bd88d44d3609c7e203c7c0c0"));
indexedBlockStore.saveBlock(block1, block1.getCumulativeDifficulty(), true);
indexedBlockStore.flush();
indexedBlockStore.saveBlock(block2, block2.getCumulativeDifficulty(), true);
indexedBlockStore.flush();
assertEquals(block1.getCumulativeDifficulty(), indexedBlockStore.getTotalDifficultyForHash(block1.getHash()));
assertEquals(block2.getCumulativeDifficulty(), indexedBlockStore.getTotalDifficultyForHash(block2.getHash()));
}
@Test
public void myTest() throws Exception {
// check that IndexedStore rebranch changes are persisted
StandaloneBlockchain bc = new StandaloneBlockchain().withGasPrice(1);
IndexedBlockStore ibs = (IndexedBlockStore) bc.getBlockchain().getBlockStore();
Block b1 = bc.createBlock();
Block b2 = bc.createBlock();
Block b2_ = bc.createForkBlock(b1);
Assert.assertTrue(bc.getBlockchain().getBestBlock().isEqual(b2));
Block b3_ = bc.createForkBlock(b2_);
Assert.assertTrue(bc.getBlockchain().getBestBlock().isEqual(b3_));
Block sb2 = bc.getBlockchain().getBlockStore().getChainBlockByNumber(2);
Block sb3 = bc.getBlockchain().getBlockStore().getChainBlockByNumber(3);
Assert.assertTrue(sb2.isEqual(b2_));
Assert.assertTrue(sb3.isEqual(b3_));
Block b4_ = bc.createBlock();
bc.getBlockchain().flush();
IndexedBlockStore ibs1 = new IndexedBlockStore();
ibs1.init(ibs.indexDS, ibs.blocksDS);
sb2 = ibs1.getChainBlockByNumber(2);
sb3 = ibs1.getChainBlockByNumber(3);
Block sb4 = ibs1.getChainBlockByNumber(4);
Assert.assertTrue(sb2.isEqual(b2_));
Assert.assertTrue(sb3.isEqual(b3_));
Assert.assertTrue(sb4.isEqual(b4_));
}
// todo: test this
// public byte[] getBlockHashByNumber(long blockNumber)
}