use of neo.model.core.Transaction 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 neo.model.core.Transaction in project neo-java by coranos.
the class BlockDbMapDbImpl method getTransactionWithAccountList.
@Override
public List<Transaction> getTransactionWithAccountList(final UInt160 account) {
final List<Transaction> transactionList = new ArrayList<>();
final BTreeMap<byte[], byte[]> transactionByAccountAndIndexMap = getTransactionByAccountAndIndexMap();
final BTreeMap<byte[], Long> transactionByAccountMaxIndexMap = getTransactionByAccountMaxIndexMap();
final byte[] accountBa = account.toByteArray();
final long maxIndex = transactionByAccountMaxIndexMap.get(accountBa);
for (long ix = 0; ix < maxIndex; ix++) {
final byte[] accountKeyBa = getAccountKey(accountBa, ix);
final byte[] ba = transactionByAccountAndIndexMap.get(accountKeyBa);
final ByteBuffer bb = ByteBuffer.wrap(ba);
final Transaction transaction = new Transaction(bb);
transactionList.add(transaction);
}
return transactionList;
}
use of neo.model.core.Transaction in project neo-java by coranos.
the class BlockDbMapDbImpl method updateAssetAndValueByAccountMap.
/**
* updates the asset and value by account map.
*
* @param block
* the block to update.
* @param reverse
* if true, reverse the update.
*/
private void updateAssetAndValueByAccountMap(final Block block, final boolean reverse) {
final BTreeMap<byte[], byte[]> assetAndValueByAccountMap = getAssetAndValueByAccountMap();
final BTreeMap<byte[], byte[]> transactionByAccountAndIndexMap = getTransactionByAccountAndIndexMap();
final BTreeMap<byte[], Long> transactionByAccountMaxIndexMap = getTransactionByAccountMaxIndexMap();
final BTreeMap<byte[], Boolean> transactionOutputSpentStateMap = getTransactionOutputSpentStateMap();
LOG.debug("updateAssetAndValueByAccountMap STARTED block;{};reverse;{};numberOfAccounts:{}", block.getIndexAsLong(), reverse, assetAndValueByAccountMap.size());
for (final Transaction t : block.getTransactionList()) {
if (LOG.isDebugEnabled()) {
LOG.debug("updateAssetAndValueByAccountMap INTERIM tx:{}", t.getHash());
}
for (final CoinReference cr : t.inputs) {
if (LOG.isDebugEnabled()) {
LOG.debug("updateAssetAndValueByAccountMap INTERIM cr:{}", cr.toJSONObject());
}
final byte[] crBa = cr.toByteArray();
if (!transactionOutputSpentStateMap.containsKey(crBa)) {
throw new RuntimeException("referenced transaction output was never a transaction input:" + cr);
}
final boolean oldSpendState;
final boolean newSpendState;
if (reverse) {
oldSpendState = true;
newSpendState = false;
} else {
oldSpendState = false;
newSpendState = true;
}
if (transactionOutputSpentStateMap.get(crBa) == oldSpendState) {
transactionOutputSpentStateMap.put(crBa, newSpendState);
final UInt256 prevHashReversed = cr.prevHash.reverse();
final Transaction tiTx = getTransactionWithHash(prevHashReversed);
if (tiTx == null) {
throw new RuntimeException("no transaction with prevHash:" + prevHashReversed + " in block[1] " + block.hash + " index[1] " + block.getIndexAsLong());
}
final int prevIndex = cr.prevIndex.asInt();
if (prevIndex >= tiTx.outputs.size()) {
throw new RuntimeException("prevIndex:" + prevIndex + " exceeds output size:" + tiTx.outputs.size() + "; in block[2] " + block.hash + " index[2] " + block.getIndexAsLong());
}
final TransactionOutput ti = tiTx.outputs.get(prevIndex);
final UInt160 input = ti.scriptHash;
final byte[] inputBa = input.toByteArray();
final Map<UInt256, Fixed8> accountAssetValueMap = ensureAccountExists(assetAndValueByAccountMap, inputBa);
if (LOG.isDebugEnabled()) {
LOG.debug("TI beforeMap {}", accountAssetValueMap);
}
if (!accountAssetValueMap.containsKey(ti.assetId)) {
accountAssetValueMap.put(ti.assetId, ModelUtil.FIXED8_ZERO);
}
final Fixed8 oldValue = accountAssetValueMap.get(ti.assetId);
final Fixed8 newValue;
if (reverse) {
newValue = ModelUtil.add(ti.value, oldValue);
} else {
newValue = ModelUtil.subtract(ti.value, oldValue);
}
if (LOG.isDebugEnabled()) {
LOG.debug("updateAssetAndValueByAccountMap INTERIM input;{};", ModelUtil.scriptHashToAddress(input));
LOG.debug("updateAssetAndValueByAccountMap INTERIM ti.assetId:{} oldValue:{};", ti.assetId, oldValue);
LOG.debug("updateAssetAndValueByAccountMap INTERIM ti.assetId:{} to.value:{};", ti.assetId, ti.value);
LOG.debug("updateAssetAndValueByAccountMap INTERIM ti.assetId:{} newValue:{};", ti.assetId, newValue);
}
if (newValue.equals(ModelUtil.FIXED8_ZERO)) {
accountAssetValueMap.remove(ti.assetId);
} else {
accountAssetValueMap.put(ti.assetId, newValue);
}
if (accountAssetValueMap.isEmpty()) {
assetAndValueByAccountMap.remove(inputBa);
} else {
putAssetValueMap(assetAndValueByAccountMap, inputBa, accountAssetValueMap);
}
if (LOG.isDebugEnabled()) {
LOG.debug("TI afterMap {}", ensureAccountExists(assetAndValueByAccountMap, inputBa));
}
} else {
if (reverse) {
throw new RuntimeException("referenced transaction output is not already spent:" + cr);
} else {
throw new RuntimeException("referenced transaction output is already spent:" + cr);
}
}
}
try {
for (int outputIx = 0; outputIx < t.outputs.size(); outputIx++) {
final TransactionOutput to = t.outputs.get(outputIx);
if (LOG.isDebugEnabled()) {
LOG.debug("updateAssetAndValueByAccountMap INTERIM to:{}", to.toJSONObject());
}
final UInt160 output = to.scriptHash;
final byte[] outputBa = output.toByteArray();
final Map<UInt256, Fixed8> accountAssetValueMap = ensureAccountExists(assetAndValueByAccountMap, outputBa);
if (LOG.isDebugEnabled()) {
LOG.debug("TO beforeMap {}", accountAssetValueMap);
}
if (!accountAssetValueMap.containsKey(to.assetId)) {
accountAssetValueMap.put(to.assetId, ModelUtil.FIXED8_ZERO);
}
final Fixed8 oldValue = accountAssetValueMap.get(to.assetId);
if (LOG.isDebugEnabled()) {
LOG.debug("updateAssetAndValueByAccountMap INTERIM output;{};", ModelUtil.scriptHashToAddress(output));
LOG.debug("updateAssetAndValueByAccountMap INTERIM to.assetId:{} oldValue:{};", to.assetId, oldValue);
LOG.debug("updateAssetAndValueByAccountMap INTERIM to.assetId:{} to.value:{};", to.assetId, to.value);
}
final Fixed8 newValue;
if (reverse) {
newValue = ModelUtil.subtract(to.value, oldValue);
} else {
newValue = ModelUtil.add(oldValue, to.value);
}
accountAssetValueMap.put(to.assetId, newValue);
if (accountAssetValueMap.isEmpty()) {
assetAndValueByAccountMap.remove(outputBa);
} else {
putAssetValueMap(assetAndValueByAccountMap, outputBa, accountAssetValueMap);
}
if (LOG.isDebugEnabled()) {
LOG.debug("updateAssetAndValueByAccountMap INTERIM to.assetId:{} newValue:{};", to.assetId, newValue);
LOG.debug("TO afterMap {}", ensureAccountExists(assetAndValueByAccountMap, outputBa));
}
final CoinReference cr = new CoinReference(t.getHash().reverse(), new UInt16(outputIx));
if (reverse) {
transactionOutputSpentStateMap.remove(cr.toByteArray());
} else {
transactionOutputSpentStateMap.put(cr.toByteArray(), false);
}
}
final byte[] tBa = t.toByteArray();
final long index;
if (transactionByAccountMaxIndexMap.containsKey(tBa)) {
index = transactionByAccountMaxIndexMap.get(tBa);
} else {
index = 0;
}
transactionByAccountMaxIndexMap.put(tBa, index + 1);
final byte[] accountKeyBa = getAccountKey(tBa, index);
transactionByAccountAndIndexMap.put(accountKeyBa, tBa);
} catch (final RuntimeException e) {
final String msg = "error processing transaction type " + t.type + " hash " + t.getHash();
throw new RuntimeException(msg, e);
}
}
LOG.debug("updateAssetAndValueByAccountMap SUCCESS block;{};numberOfAccounts:{}", block.getIndexAsLong(), assetAndValueByAccountMap.size());
}
use of neo.model.core.Transaction 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;
}
use of neo.model.core.Transaction in project neo-java by coranos.
the class RpcServerUtil method getAddressAssetMap.
/**
* returns the address asset map.
*
* @param blockDb
* the block database to use.
* @param transaction
* the transaction to use.
* @return the address asset map.
*/
public static Map<UInt160, Map<UInt256, Long>> getAddressAssetMap(final BlockDb blockDb, final Transaction transaction) {
final Map<UInt160, Map<UInt256, Long>> friendAssetMap = new TreeMap<>();
for (final CoinReference cr : transaction.inputs) {
final UInt256 prevHashReversed = cr.prevHash.reverse();
final Transaction tiTx = blockDb.getTransactionWithHash(prevHashReversed);
if (tiTx == null) {
throw new RuntimeException("no transaction with prevHash:" + prevHashReversed);
}
final TransactionOutput ti = tiTx.outputs.get(cr.prevIndex.asInt());
final UInt160 input = ti.scriptHash;
if ((ti.assetId.equals(ModelUtil.NEO_HASH)) || (ti.assetId.equals(ModelUtil.GAS_HASH))) {
MapUtil.increment(friendAssetMap, input, ti.assetId, ti.value.value, TreeMap.class);
}
}
for (final TransactionOutput to : transaction.outputs) {
final UInt160 output = to.scriptHash;
if ((to.assetId.equals(ModelUtil.NEO_HASH)) || (to.assetId.equals(ModelUtil.GAS_HASH))) {
MapUtil.increment(friendAssetMap, output, to.assetId, -to.value.value, TreeMap.class);
}
}
return friendAssetMap;
}
Aggregations