use of neo.model.core.CoinReference in project neo-java by coranos.
the class AbstractJsonMockBlockDb method getUnspentTransactionOutputListMap.
@Override
public Map<UInt256, Map<TransactionOutput, CoinReference>> getUnspentTransactionOutputListMap(final UInt160 account) {
final Map<UInt256, Map<TransactionOutput, CoinReference>> assetIdTxoMap = new TreeMap<>();
final JSONArray mockBlockDb = getMockBlockDb();
for (int ix = 0; ix < mockBlockDb.length(); ix++) {
final JSONObject mockBlock = mockBlockDb.getJSONObject(ix);
final Block block = getBlock(mockBlock, true);
for (int txIx = 0; txIx < block.getTransactionList().size(); txIx++) {
final Transaction transaction = block.getTransactionList().get(txIx);
for (final TransactionOutput output : transaction.outputs) {
if (output.scriptHash.equals(account)) {
if (!assetIdTxoMap.containsKey(output.assetId)) {
assetIdTxoMap.put(output.assetId, new TreeMap<>());
}
final CoinReference cr = new CoinReference(transaction.getHash(), new UInt16(txIx));
assetIdTxoMap.get(output.assetId).put(output, cr);
}
}
}
}
return assetIdTxoMap;
}
use of neo.model.core.CoinReference in project neo-java by coranos.
the class MockUtil method getCoinReference001.
public static CoinReference getCoinReference001() {
final int minSize = UInt256.SIZE + UInt16.SIZE;
final byte[] ba = new byte[minSize];
final UInt256 txHash = GenesisBlockUtil.GENESIS_BLOCK.getTransactionList().get(3).getHash();
System.arraycopy(txHash.getBytesCopy(), 0, ba, 0, txHash.getByteLength());
return new CoinReference(ByteBuffer.wrap(ba));
}
use of neo.model.core.CoinReference in project neo-java by coranos.
the class TestAccountPng method test001GetAccountSankey.
@Test
public void test001GetAccountSankey() throws JSONException, IOException {
LOG.debug("STARTED png");
final LocalNodeData localNodeData = CONTROLLER.getLocalNodeData();
final BlockDb blockDb = localNodeData.getBlockDb();
final long maxIndex = blockDb.getHeaderOfBlockWithMaxIndex().getIndexAsLong();
final CoinData neoData = new CoinData();
final CoinData gasData = new CoinData();
final Map<UInt256, CoinData> coinDataMap = new TreeMap<>();
coinDataMap.put(ModelUtil.NEO_HASH, neoData);
coinDataMap.put(ModelUtil.GAS_HASH, gasData);
final File dir = new File("/Users/dps/git-coranos.github.io/neo/charts");
final Map<UInt256, File> coinFileMap = new TreeMap<>();
coinFileMap.put(ModelUtil.NEO_HASH, new File(dir, "neo-account.png"));
coinFileMap.put(ModelUtil.GAS_HASH, new File(dir, "gas-account.png"));
long startMs = -1;
for (long blockIx = 0; blockIx <= maxIndex; blockIx++) {
LOG.debug("STARTED png {} of {} ", blockIx, maxIndex);
final Block block = blockDb.getFullBlockFromHeight(blockIx);
for (final Transaction t : block.getTransactionList()) {
// update assets based on tx inputs.
for (final CoinReference cr : t.inputs) {
final TransactionOutput ti = ModelUtil.getTransactionOutput(blockDb, cr);
if (coinDataMap.containsKey(ti.assetId)) {
final CoinData coinData = coinDataMap.get(ti.assetId);
final UInt160 input = ti.scriptHash;
if (!coinData.accountValueMap.containsKey(input)) {
coinData.accountValueMap.put(input, ModelUtil.FIXED8_ZERO);
coinData.newAccountSet.add(input);
}
final Fixed8 oldValue = coinData.accountValueMap.get(input);
final Fixed8 newValue = ModelUtil.subtract(ti.value, oldValue);
if (newValue.equals(ModelUtil.FIXED8_ZERO)) {
coinData.accountValueMap.remove(input);
} else {
coinData.accountValueMap.put(input, newValue);
}
}
}
// update assets based on tx outputs.
for (int outputIx = 0; outputIx < t.outputs.size(); outputIx++) {
final TransactionOutput to = t.outputs.get(outputIx);
final UInt160 output = to.scriptHash;
if (coinDataMap.containsKey(to.assetId)) {
final CoinData coinData = coinDataMap.get(to.assetId);
coinData.txAccountSet.add(output);
if (!coinData.accountValueMap.containsKey(output)) {
coinData.accountValueMap.put(output, ModelUtil.FIXED8_ZERO);
coinData.newAccountSet.add(output);
}
final Fixed8 oldValue = coinData.accountValueMap.get(output);
final Fixed8 newValue = ModelUtil.add(oldValue, to.value);
if (newValue.equals(ModelUtil.FIXED8_ZERO)) {
coinData.accountValueMap.remove(output);
} else {
coinData.accountValueMap.put(output, newValue);
}
}
}
for (final UInt256 assetId : coinDataMap.keySet()) {
final CoinData coinData = coinDataMap.get(assetId);
for (final UInt160 txAccount : coinData.txAccountSet) {
MapUtil.increment(coinData.newAccountTxCountMap, txAccount);
}
coinData.txAccountSet.clear();
}
}
final Timestamp blockTs = block.getTimestamp();
if (startMs < 0) {
startMs = blockTs.getTime();
}
final long ms = blockTs.getTime() - startMs;
if (ms > (86400 * 1000)) {
final String targetDateStr = DATE_FORMAT.format(blockTs);
for (final UInt256 assetId : coinDataMap.keySet()) {
final CoinData coinData = coinDataMap.get(assetId);
final List<UInt160> accountList = new ArrayList<>();
accountList.addAll(coinData.accountValueMap.keySet());
Collections.sort(accountList, new Comparator<UInt160>() {
@Override
public int compare(final UInt160 account1, final UInt160 account2) {
final Long value1 = coinData.accountValueMap.get(account1).value;
final Long value2 = coinData.accountValueMap.get(account2).value;
return value1.compareTo(value2);
}
});
Collections.reverse(accountList);
long maxTx = 0;
long totalValue = 0;
{
final List<DrawingData> drawingData = new ArrayList<>();
coinData.drawingDataList.add(drawingData);
int startDayPixel = 0;
int visibleAccountCount = 0;
for (final UInt160 account : accountList) {
totalValue += coinData.accountValueMap.get(account).value;
}
for (final UInt160 account : accountList) {
final int scaleLength = getScaleLength(coinData.accountValueMap, account, totalValue);
if (scaleLength != 0) {
visibleAccountCount++;
}
MapUtil.touch(coinData.newAccountTxCountMap, account);
maxTx = Math.max(maxTx, coinData.newAccountTxCountMap.get(account));
}
final float greenStep = 1.0f / visibleAccountCount;
final float redStep = 1.0f / maxTx;
float green = 1.0f;
for (final UInt160 account : accountList) {
final int scaleLength = getScaleLength(coinData.accountValueMap, account, totalValue);
if (scaleLength != 0) {
final float blue;
if (coinData.newAccountSet.contains(account)) {
blue = 1.0f;
} else {
blue = 0.0f;
}
float red = 0.0f;
if (coinData.newAccountTxCountMap.containsKey(account)) {
red = redStep * coinData.newAccountTxCountMap.get(account);
} else {
red = 0.0f;
}
drawingData.add(new DrawingData(startDayPixel, scaleLength, red, green, blue));
}
green -= greenStep;
startDayPixel += scaleLength;
}
}
final BufferedImage im = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
final Graphics2D g = (Graphics2D) im.getGraphics();
g.scale((WIDTH * 1.0) / coinData.drawingDataList.size(), 1.0 / HEIGHT_SUBPIXELS);
for (int x = 0; x < coinData.drawingDataList.size(); x++) {
final List<DrawingData> drawingData = coinData.drawingDataList.get(x);
for (final DrawingData drawing : drawingData) {
g.setColor(new Color(drawing.r, drawing.g, drawing.b));
g.fillRect(x, drawing.y, 1, drawing.h);
g.setColor(Color.black);
g.drawLine(x, drawing.y, x + 1, drawing.y);
}
}
g.dispose();
final File file = coinFileMap.get(assetId);
ImageIO.write(im, "png", file);
LOG.info("INTERIM file {}, {} of {}, date {}, accountList {}, tx {}, value {}", file.getName(), INTEGER_FORMAT.format(blockIx), INTEGER_FORMAT.format(maxIndex), targetDateStr, INTEGER_FORMAT.format(accountList.size()), INTEGER_FORMAT.format(maxTx), INTEGER_FORMAT.format(totalValue / ModelUtil.DECIMAL_DIVISOR));
startMs = blockTs.getTime();
coinData.newAccountSet.clear();
coinData.newAccountTxCountMap.clear();
}
}
}
LOG.debug("SUCCESS png");
}
use of neo.model.core.CoinReference 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.CoinReference 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