IndexedBlockStore的用法 - ethereumj

半兽人 发表于: 2018-05-23   最后更新时间: 2018-05-23 17:31:46  
{{totalSubscript}} 订阅, 3,630 游览

类:org.ethereum.db.IndexedBlockStore

此类为数据源映射类,别的业务都通过此类,来统一作为入口,进行查询、存储区块链的区块信息等。此类封装了底层使用的是什么样的资源做存储,数据源可以是缓存,也可以是rockdb,可以是leveldb,也可以是数据库,等等。都由该类统一映射。

## 内部类
BlockInfo

## 方法
init
getBestBlock
getBlockHashByNumber
flush
saveBlock
addInternalBlock
putBlockInfo
getBlocksByNumber
getChainBlockByNumber
getBlockByHash
isBlockExist
getTotalDifficultyForHash
getTotalDifficulty
updateTotDifficulties
getMaxNumber
getListHashesEndWith
getListHeadersEndWith
getListBlocksEndWith
getListBlocksEndWithInner
reBranch
getListHashesStartWith
printChain
getBlockInfoForLevel
setBlockInfoForLevel
getBlockInfoForHash

## 参数
load
close
logger
indexDS
index
blocksDS
blocks
BLOCK_INFO_SERIALIZER

有2个核心的成员变量:

DataSourceArray<List<BlockInfo>> index;
ObjectDataSource<Block> blocks;
  • index 存储一个区块链中区块号和区块描述信息。key:value = 区块号:区块描述信息。
  • blocks 存储区块链中的区块hash和区块全信息。key:value = 区块hash:区块全信息。

测试

进行一个简单的测试,来感受一下此类的作用。

package org.ethereum.core;

import org.ethereum.config.SystemProperties;
import org.ethereum.datasource.DbSource;
import org.ethereum.datasource.inmem.HashMapDB;
import org.ethereum.datasource.rocksdb.RocksDbDataSource;
import org.ethereum.db.IndexedBlockStore;
import org.ethereum.util.FileUtil;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
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.ArrayList;
import java.util.List;
import java.util.Random;

import static java.math.BigInteger.ZERO;
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;

    @AfterClass
    public static void cleanup() {
        SystemProperties.resetToDefault();
    }

    /**
     * 加载`blockstore/load.dmp`,生成一个block集合,为后续测试做准备。
     */
    @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
    public void test1() {
        IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
        // 注意,初始化的参数是new HashMapDB<byte[],是个缓存,所以后续的存储都是保存到缓存里了。唯一的差别就是这里了
        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
    public void test4() throws IOException {

        BigInteger bi = new BigInteger(32, new Random());
        String testDir = "test_db_" + bi;
        SystemProperties.getDefault().setDataBaseDir(testDir);

        RocksDbDataSource indexDB = new RocksDbDataSource("index");
        indexDB.init();

        DbSource blocksDB = new RocksDbDataSource("blocks");
        blocksDB.init();

        IndexedBlockStore indexedBlockStore = new IndexedBlockStore();
        // 注意,初始化的参数是rockDB,一个用于index,一个用于blocks。所以后续的所有操作都将直接写到磁盘里啦。
        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 RocksDbDataSource("index");
        indexDB.init();

        blocksDB = new RocksDbDataSource("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);
    }
}

唯一的区别就在初始化那里了。

更新于 2018-05-23

查看ethereumj更多相关的文章或提一个关于ethereumj的问题,也可以与我们一起分享文章