/* * Follow the Bitcoin * Copyright (C) 2014 Danno Ferrin * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package com.shemnon.btc.bitcore; import com.shemnon.btc.coinbase.CBPriceHistory; import com.shemnon.btc.model.IBase; import com.shemnon.btc.model.ICoin; import com.shemnon.btc.model.ITx; import javax.json.JsonNumber; import javax.json.JsonObject; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * There is no such thing as a coin, this is an abstraction of tx input/output * Created by shemnon on 2 Mar 2014. */ public class BCCoin extends BitcoreBase implements ICoin { static Map<String, BCCoin> coincache = new ConcurrentHashMap<>(); String compkey; String sourceTxID; String coinbase; String spendTxID; int sourceN; String addr; double value; private BCCoin() { } public static BCCoin query(String coinKey) { if (coinKey == null) return null; if (!coincache.containsKey(coinKey)) { IBase.checkOffThread(); BCTx.query(coinKey.split("#")[0]); } return coincache.get(coinKey); } static BCCoin cacheFromInput(JsonObject j, String spendTxID) { String txid = j.getString("txid", null); if (txid == null) { txid = "@" + j.getString("coinbase"); } int n = j.getInt("vout", j.getInt("sequence", -1)); String key = txid + "#" + n; BCCoin ci = coincache.get(key); if (ci == null) { ci = new BCCoin(); if (txid.startsWith("@")) { ci.coinbase = txid.substring(1); } else { ci.sourceTxID = txid; } ci.spendTxID = spendTxID; ci.sourceN = n; ci.addr = j.getString("addr", null); try { JsonNumber num = j.getJsonNumber("value"); if (num != null) { ci.value = num.doubleValue(); } } catch (Exception e) { System.out.println(j); e.printStackTrace(); } ci.compkey = key; coincache.put(key, ci); } return ci; } static BCCoin cacheFromOutput(JsonObject j, String sourceTxID) { int n = j.getInt("n"); String key = sourceTxID + "#" + n; BCCoin ci = coincache.get(key); if (ci == null) { ci = new BCCoin(); ci.sourceTxID = sourceTxID; ci.spendTxID = j.getString("spentTxId", null); ci.sourceN = n; ci.addr = j.getJsonObject("scriptPubKey").getJsonArray("addresses").getString(0); try { ci.value = j.getJsonNumber("value").doubleValue(); } catch (Exception e) { System.out.println(j); e.printStackTrace(); } ci.compkey = key; coincache.put(key, ci); } return ci; } public String getAddr() { return addr; } public String getCompkey() { return compkey; } public double getValue() { return value; } public long getValueSatoshi() { return (long)(value * 100000000L); } public double getValueUSD() { if (getSourceTX().isConfirmed()) { return CBPriceHistory.getInstance().getPrice(getSourceTX().getTimeMs()).orElse(0.0) * value; } else { return -1.0; } } public String getSourceTXID() { return sourceTxID; } public String getTargetTXID() { return spendTxID; } public ITx getSourceTX() { return BCTx.query(sourceTxID); } public ITx getTargetTX() { return BCTx.query(spendTxID); } public boolean isSpent() { return spendTxID != null; } public boolean isCoinbase() { return coinbase != null; } public String toString() { if (showEdgeBTC.get()) { return BTC_FORMAT.format(getValue()); } else if (showEdgeUSD.get()) { return USD_FORMAT.format(getValueUSD()); } else if (showEdgeAddr.get()) { return IBase.shortHash(getAddr()); } else { return ""; } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; BCCoin bcCoin = (BCCoin) o; return !(compkey != null ? !compkey.equals(bcCoin.compkey) : bcCoin.compkey != null); } @Override public int hashCode() { return compkey != null ? compkey.hashCode() : 0; } @Override public String dump() { return "{\"type\":\"BCBlock\", \"sourceTX\":\"" + sourceTxID + "\", \"n\":" + sourceN + "}"; } }