package jelectrum; import java.util.HashMap; import java.util.TreeMap; import java.util.HashSet; import java.util.Map; import java.util.ArrayList; import org.bitcoinj.core.StoredBlock; import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Block; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.store.BlockStore; public class BlockChainCache { private BlockStore store; private Map<Integer, Sha256Hash> height_map; private volatile Sha256Hash last_head; private EventLog event_log; public BlockChainCache(BlockStore store, Map<Integer, Sha256Hash> height_map, EventLog event_log) { this.store = store; this.height_map = height_map; this.event_log = event_log; } public void update(Jelectrum jelly, StoredBlock new_head) throws org.bitcoinj.store.BlockStoreException { last_head = new_head.getHeader().getHash(); //event_log.log("BlockChainCache: chain update, new head: " + new_head.getHeader().getHash() + " - " + new_head.getHeight()); Sha256Hash genesis_hash = jelly.getNetworkParameters().getGenesisBlock().getHash(); StoredBlock cur = new_head; TreeMap<Integer, Sha256Hash> to_write = new TreeMap<>(); int reorg=0; while(true) { int height = cur.getHeight(); Sha256Hash curr_hash = cur.getHeader().getHash(); Sha256Hash exist_hash = getBlockHashAtHeight(height); if ((exist_hash != null) && (!exist_hash.equals(curr_hash))) { reorg++; } if (curr_hash.equals(exist_hash)) break; to_write.put(height, curr_hash); if (curr_hash.equals(genesis_hash)) break; cur = cur.getPrev(store); } if (to_write.size() > 1) { event_log.log("BlockChainCache: adding " + to_write.size() + " to height map"); } /** * Write them out in order to make sure this is recoverable if interupted in the middle */ for(Map.Entry<Integer, Sha256Hash> me : to_write.entrySet()) { height_map.put(me.getKey(), me.getValue()); } if (reorg > 0) { event_log.alarm("BlockChainCache: re-org of " + reorg + " blocks found"); } } public static BlockChainCache load(Jelectrum jelly) { return new BlockChainCache(jelly.getBlockStore(), jelly.getDB().getHeightMap(), jelly.getEventLog()); } public Sha256Hash getBlockHashAtHeight(int height) { return height_map.get(height); } public boolean isBlockInMainChain(Sha256Hash hash) { try { StoredBlock sb = store.get(hash); int h = sb.getHeight(); return (hash.equals(getBlockHashAtHeight(h))); } catch(org.bitcoinj.store.BlockStoreException e) { throw new RuntimeException(e); } } public Sha256Hash getHead() { return last_head; } }