use of org.mapdb.BTreeMap in project neo-java by coranos.
the class BlockDbMapDbImpl method validate.
@Override
public void validate() {
LOG.info("STARTED validate");
try {
final Block block0 = getBlock(0, false);
if (!block0.hash.equals(GenesisBlockUtil.GENESIS_HASH)) {
throw new RuntimeException("height 0 block hash \"" + block0.hash.toHexString() + "\" does not match genesis block hash \"" + GenesisBlockUtil.GENESIS_HASH.toHexString() + "\".");
}
long lastInfoMs = System.currentTimeMillis();
long blockHeight = 0;
long lastGoodBlockIndex = -1;
final long maxBlockCount = getBlockCount();
boolean blockHeightNoLongerValid = false;
final String maxBlockCountStr;
if (LOG.isDebugEnabled() || LOG.isErrorEnabled()) {
maxBlockCountStr = NumberFormat.getIntegerInstance().format(maxBlockCount);
} else {
maxBlockCountStr = null;
}
LOG.info("INTERIM validate, clear account list STARTED");
final BTreeMap<byte[], byte[]> assetAndValueByAccountMap = getAssetAndValueByAccountMap();
assetAndValueByAccountMap.clear();
LOG.info("INTERIM validate, clear account list SUCCESS");
LOG.info("INTERIM validate, clear transaction output state STARTED");
getTransactionByAccountAndIndexMap().clear();
getTransactionByAccountMaxIndexMap().clear();
LOG.info("INTERIM validate, clear transaction output state SUCCESS");
while (blockHeight < maxBlockCount) {
final String blockHeightStr;
if (LOG.isDebugEnabled() || LOG.isErrorEnabled()) {
blockHeightStr = NumberFormat.getIntegerInstance().format(blockHeight);
} else {
blockHeightStr = null;
}
LOG.debug("INTERIM DEBUG validate {} of {} STARTED ", blockHeightStr, maxBlockCountStr);
final Block block = getBlock(blockHeight, true);
if (block == null) {
LOG.error("INTERIM validate {} of {} FAILURE, block not found in blockchain.", blockHeightStr, maxBlockCountStr);
blockHeightNoLongerValid = true;
} else if ((blockHeight != 0) && (!containsBlockWithHash(block.prevHash))) {
LOG.error("INTERIM validate {} of {} FAILURE, prevHash {} not found in blockchain.", blockHeightStr, maxBlockCountStr, block.prevHash.toHexString());
deleteBlockAtHeight(blockHeight);
blockHeightNoLongerValid = true;
} else if (block.getIndexAsLong() != blockHeight) {
LOG.error("INTERIM validate {} of {} FAILURE, indexAsLong {} does not match blockchain.", blockHeightStr, maxBlockCountStr, block.getIndexAsLong());
deleteBlockAtHeight(blockHeight);
blockHeightNoLongerValid = true;
} else if (blockHeightNoLongerValid) {
LOG.error("INTERIM validate {} of {} FAILURE, block height tainted.", blockHeightStr, maxBlockCountStr, block.getIndexAsLong());
deleteBlockAtHeight(blockHeight);
} else {
if (System.currentTimeMillis() > (lastInfoMs + 30000)) {
final String numberOfAccountsStr = NumberFormat.getIntegerInstance().format(assetAndValueByAccountMap.size());
LOG.info("INTERIM INFO validate {} of {} SUCCESS, number of accounts:{}; date:{}", blockHeightStr, maxBlockCountStr, numberOfAccountsStr, block.getTimestamp());
lastInfoMs = System.currentTimeMillis();
} else {
LOG.debug("INTERIM DEBUG validate {} of {} SUCCESS.", blockHeightStr, maxBlockCountStr);
}
final long blockIndex = block.getIndexAsLong();
int transactionIndex = 0;
final Map<ByteBuffer, byte[]> txKeyByTxHashMap = new TreeMap<>();
for (final Transaction transaction : block.getTransactionList()) {
final byte[] transactionKeyBa = getTransactionKey(blockIndex, transactionIndex);
txKeyByTxHashMap.put(ByteBuffer.wrap(transaction.getHash().toByteArray()), transactionKeyBa);
transactionIndex++;
}
putWithByteBufferKey(TRANSACTION_KEY_BY_HASH, txKeyByTxHashMap);
try {
updateAssetAndValueByAccountMap(block, false);
} catch (final Exception e) {
throw new RuntimeException("validate: error updating assets for block [" + block.getIndexAsLong() + "]" + block.hash, e);
}
lastGoodBlockIndex = block.getIndexAsLong();
}
final boolean forceSynch = (lastGoodBlockIndex % BLOCK_FORCE_SYNCH_INTERVAL) == 0;
if (forceSynch) {
LOG.info("INTERIM validate, partial commit STARTED index {}", lastGoodBlockIndex);
commitValidation(lastGoodBlockIndex);
LOG.info("INTERIM validate, partial commit SUCCESS index {}", lastGoodBlockIndex);
}
blockHeight++;
}
LOG.info("INTERIM validate, commit STARTED index {}", lastGoodBlockIndex);
commitValidation(lastGoodBlockIndex);
LOG.info("INTERIM validate, commit SUCCESS index {}", lastGoodBlockIndex);
LOG.info("SUCCESS validate");
} catch (final Exception e) {
LOG.error("FAILURE validate", e);
db.rollback();
throw new RuntimeException(e);
}
}
use of org.mapdb.BTreeMap in project neo-java by coranos.
the class BlockDbMapDbImpl method put.
@Override
public void put(final boolean forceSynch, final Block... blocks) {
synchronized (this) {
if (closed) {
return;
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("STARTED put, {} blocks", NumberFormat.getIntegerInstance().format(blocks.length));
}
try {
final BTreeMap<byte[], Long> blockIndexByHashMap = getBlockIndexByHashMap();
final BTreeMap<Long, byte[]> blockHeaderByIndexMap = getBlockHeaderByIndexMap();
for (final Block block : blocks) {
synchronized (this) {
if (closed) {
db.rollback();
return;
}
}
final long blockIndex = block.getIndexAsLong();
final long maxBlockIndex = getMaxBlockIndex();
final boolean duplicateBlock;
if ((blockIndex <= maxBlockIndex) && (blockIndex != 0) && (maxBlockIndex != 0)) {
duplicateBlock = true;
} else {
duplicateBlock = false;
}
if (duplicateBlock) {
LOG.error("duplicate block,blockIndex:{};maxBlockIndex:{};hash:{};", blockIndex, maxBlockIndex, block.hash);
} else {
final byte[] prevHashBa = block.prevHash.toByteArray();
ArrayUtils.reverse(prevHashBa);
blockIndexByHashMap.put(block.hash.toByteArray(), blockIndex);
blockHeaderByIndexMap.put(blockIndex, block.toHeaderByteArray());
int transactionIndex = 0;
final Map<Long, List<byte[]>> txKeyByBlockIxMap = new TreeMap<>();
final Map<ByteBuffer, byte[]> txByKeyMap = new TreeMap<>();
final Map<ByteBuffer, byte[]> txKeyByTxHashMap = new TreeMap<>();
txKeyByBlockIxMap.put(blockIndex, new ArrayList<>());
for (final Transaction transaction : block.getTransactionList()) {
final byte[] transactionBaseBa = transaction.toByteArray();
final byte[] transactionKeyBa = getTransactionKey(blockIndex, transactionIndex);
putList(txKeyByBlockIxMap, blockIndex, transactionKeyBa);
final ByteBuffer transactionKeyBb = ByteBuffer.wrap(transactionKeyBa);
txByKeyMap.put(transactionKeyBb, transactionBaseBa);
txKeyByTxHashMap.put(ByteBuffer.wrap(transaction.getHash().toByteArray()), transactionKeyBa);
transactionIndex++;
}
putWithByteBufferKey(TRANSACTION_KEY_BY_HASH, txKeyByTxHashMap);
putWithByteBufferKey(TRANSACTION_BY_KEY, txByKeyMap);
putWithLongKey(TRANSACTION_KEYS_BY_BLOCK_INDEX, toByteBufferValue(txKeyByBlockIxMap));
try {
updateAssetAndValueByAccountMap(block, false);
} catch (final Exception e) {
throw new RuntimeException("put: error updating assets for block " + block.hash, e);
}
updateMaxBlockIndex(blockIndex);
}
}
db.commit();
} catch (final Exception e) {
LOG.error("FAILURE put, {} blocks", NumberFormat.getIntegerInstance().format(blocks.length));
LOG.error("FAILURE put", e);
db.rollback();
throw new RuntimeException(e);
}
if (LOG.isDebugEnabled()) {
LOG.debug("SUCCESS put, {} blocks", NumberFormat.getIntegerInstance().format(blocks.length));
}
}
use of org.mapdb.BTreeMap in project neo-java by coranos.
the class BlockDbMapDbImpl method getAccountAssetValueMap.
@Override
public Map<UInt160, Map<UInt256, Fixed8>> getAccountAssetValueMap() {
LOG.info("getAccountAssetValueMap STARTED");
final Map<UInt160, Map<UInt256, Fixed8>> accountAssetValueMap = new TreeMap<>();
final BTreeMap<byte[], byte[]> assetAndValueByAccountMap = getAssetAndValueByAccountMap();
LOG.info("getAccountAssetValueMap INTERIM assetAndValueByAccountMap.size:{};", assetAndValueByAccountMap.size());
for (final byte[] key : assetAndValueByAccountMap.getKeys()) {
final byte[] value = assetAndValueByAccountMap.get(key);
final UInt160 account = new UInt160(key);
final Map<UInt256, Fixed8> map = getAssetValueMapFromByteArray(value);
accountAssetValueMap.put(account, map);
}
LOG.info("getAccountAssetValueMap SUCCESS, count:{}", accountAssetValueMap.size());
return accountAssetValueMap;
}
use of org.mapdb.BTreeMap in project neo-java by coranos.
the class BlockDbMapDbImpl method getUnspentTransactionOutputListMap.
@Override
public Map<UInt256, Map<TransactionOutput, CoinReference>> getUnspentTransactionOutputListMap(final UInt160 account) {
final List<Transaction> transactionList = getTransactionWithAccountList(account);
final BTreeMap<byte[], Boolean> transactionOutputSpentStateMap = getTransactionOutputSpentStateMap();
final Map<UInt256, Map<TransactionOutput, CoinReference>> assetIdTxoMap = new TreeMap<>();
final BTreeMap<byte[], byte[]> txKeyByHashMap = getTransactionKeyByTransactionHashMap();
for (final Transaction transaction : transactionList) {
final byte[] hashBa = transaction.getHash().toByteArray();
final byte[] txKeyBa = txKeyByHashMap.get(hashBa);
for (final TransactionOutput to : transaction.outputs) {
if (to.scriptHash.equals(account)) {
final byte[] toBa = to.toByteArray();
if (transactionOutputSpentStateMap.containsKey(toBa)) {
if (transactionOutputSpentStateMap.get(toBa) == true) {
if (!assetIdTxoMap.containsKey(to.assetId)) {
assetIdTxoMap.put(to.assetId, new TreeMap<>());
}
final int txIx = getTransactionIndexInBlockFromTransactionKey(txKeyBa);
final CoinReference cr = new CoinReference(transaction.getHash(), new UInt16(txIx));
assetIdTxoMap.get(to.assetId).put(to, cr);
}
}
}
}
}
return assetIdTxoMap;
}
Aggregations