Search in sources :

Example 21 with TransactionOutput

use of neo.model.core.TransactionOutput 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());
}
Also used : CoinReference(neo.model.core.CoinReference) TransactionOutput(neo.model.core.TransactionOutput) Transaction(neo.model.core.Transaction) UInt160(neo.model.bytes.UInt160) Fixed8(neo.model.bytes.Fixed8) UInt16(neo.model.bytes.UInt16) UInt256(neo.model.bytes.UInt256)

Example 22 with TransactionOutput

use of neo.model.core.TransactionOutput 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;
}
Also used : CoinReference(neo.model.core.CoinReference) TransactionOutput(neo.model.core.TransactionOutput) TreeMap(java.util.TreeMap) BTreeMap(org.mapdb.BTreeMap) Transaction(neo.model.core.Transaction) UInt16(neo.model.bytes.UInt16) Map(java.util.Map) TreeMap(java.util.TreeMap) BTreeMap(org.mapdb.BTreeMap) UInt256(neo.model.bytes.UInt256)

Example 23 with TransactionOutput

use of neo.model.core.TransactionOutput 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;
}
Also used : CoinReference(neo.model.core.CoinReference) TransactionOutput(neo.model.core.TransactionOutput) Transaction(neo.model.core.Transaction) UInt160(neo.model.bytes.UInt160) TreeMap(java.util.TreeMap) Map(java.util.Map) TreeMap(java.util.TreeMap) UInt256(neo.model.bytes.UInt256)

Example 24 with TransactionOutput

use of neo.model.core.TransactionOutput in project neo-java by coranos.

the class RpcServerUtil method toUnspentJSONArray.

/**
 * converts a map of TransactionOutputs and CoinReferences to a json array of
 * unspent transaction outputs.
 *
 * @param map
 *            the map to use.
 * @param withDecimals
 *            if true, the value should have decimals.
 * @return the json array of unspent transaction outputs.
 */
private static JSONArray toUnspentJSONArray(final Map<TransactionOutput, CoinReference> map, final boolean withDecimals) {
    if (map == null) {
        return null;
    }
    final JSONArray array = new JSONArray();
    for (final TransactionOutput output : map.keySet()) {
        final CoinReference cr = map.get(output);
        final JSONObject elt = toUnspentJSONObject(withDecimals, output, cr);
        array.put(elt);
    }
    return array;
}
Also used : CoinReference(neo.model.core.CoinReference) TransactionOutput(neo.model.core.TransactionOutput) JSONObject(org.json.JSONObject) JSONArray(org.json.JSONArray)

Example 25 with TransactionOutput

use of neo.model.core.TransactionOutput in project neo-java by coranos.

the class TestCoreToJson method test010TransactionOutput.

/**
 * test TransactionOutput.
 */
@Test
public void test010TransactionOutput() {
    final TransactionOutput transactionOutput = MockUtil.getTransactionOutput000();
    final String expectedStrRaw = TestUtil.getJsonTestResourceAsString(TEST_PACKAGE, getClass().getSimpleName(), "test010TransactionOutput");
    final String expectedStr = new JSONObject(expectedStrRaw).toString();
    final String actualStr = transactionOutput.toString();
    Assert.assertEquals(TestUtil.RESPONSES_MUST_MATCH, expectedStr, actualStr);
}
Also used : TransactionOutput(neo.model.core.TransactionOutput) JSONObject(org.json.JSONObject) Test(org.junit.Test)

Aggregations

TransactionOutput (neo.model.core.TransactionOutput)25 Transaction (neo.model.core.Transaction)17 JSONObject (org.json.JSONObject)16 UInt256 (neo.model.bytes.UInt256)15 TreeMap (java.util.TreeMap)11 Fixed8 (neo.model.bytes.Fixed8)11 CoinReference (neo.model.core.CoinReference)10 JSONArray (org.json.JSONArray)10 UInt160 (neo.model.bytes.UInt160)9 Block (neo.model.core.Block)9 Map (java.util.Map)8 Test (org.junit.Test)6 BlockDb (neo.model.db.BlockDb)5 UInt16 (neo.model.bytes.UInt16)4 Timestamp (java.sql.Timestamp)3 LocalNodeData (neo.network.model.LocalNodeData)3 JdbcTemplate (org.springframework.jdbc.core.JdbcTemplate)3 BufferedOutputStream (java.io.BufferedOutputStream)2 DataOutputStream (java.io.DataOutputStream)2 FileOutputStream (java.io.FileOutputStream)2