001package org.consensusj.bitcoin.json.pojo; 002 003import com.fasterxml.jackson.annotation.JsonCreator; 004import com.fasterxml.jackson.annotation.JsonProperty; 005import org.bitcoinj.base.Address; 006import org.bitcoinj.core.LockTime; 007import org.bitcoinj.script.Script; 008import org.consensusj.bitcoin.json.conversion.HexUtil; 009import org.bitcoinj.base.Coin; 010import org.bitcoinj.base.Sha256Hash; 011import org.bitcoinj.core.Transaction; 012 013import java.time.Instant; 014import java.util.ArrayList; 015import java.util.List; 016import java.util.stream.Collectors; 017 018/** 019 * RawTransaction POJO 020 */ 021// "hash" property added (present in Bitcoin 0.13) 022public class RawTransactionInfo { 023 private final String hex; 024 private final Sha256Hash txid; 025 private final long version; 026 private final LockTime lockTime; 027 private final List<Vin> vin; 028 private final List<Vout> vout; 029 private final Sha256Hash blockhash; 030 private final int confirmations; 031 private final Instant time; 032 public final Instant blocktime; 033 034 @JsonCreator 035 public RawTransactionInfo(@JsonProperty("hex") String hex, 036 @JsonProperty("txid") Sha256Hash txid, 037 @JsonProperty("version") long version, 038 @JsonProperty("locktime") long locktime, 039 @JsonProperty("vin") VinList vin, 040 @JsonProperty("vout") VoutList vout, 041 @JsonProperty("blockhash") Sha256Hash blockhash, 042 @JsonProperty("confirmations") int confirmations, 043 @JsonProperty("time") long time, 044 @JsonProperty("blocktime") long blocktime) { 045 this.hex = hex; 046 this.txid = txid; 047 this.version = version; 048 this.lockTime = LockTime.of(locktime); 049 this.vin = vin; 050 this.vout = vout; 051 this.blockhash = blockhash; 052 this.confirmations = confirmations; 053 this.time = Instant.ofEpochSecond(time); 054 this.blocktime = Instant.ofEpochSecond(blocktime); 055 } 056 057 /** 058 * Construct from a bitcoinj transaction 059 * @param transaction A bitcoinj confirmed or unconfirmed transaction 060 */ 061 public RawTransactionInfo(Transaction transaction) { 062 this.hex = HexUtil.bytesToHexString(transaction.bitcoinSerialize()); 063 this.txid = transaction.getTxId(); 064 this.version = transaction.getVersion(); 065 this.lockTime = transaction.lockTime(); 066 this.blockhash = null; // For now 067 this.confirmations = transaction.getConfidence().getDepthInBlocks(); 068 this.time = Instant.ofEpochSecond(0); // TODO: block header time of block including transaction 069 this.blocktime = this.time; // same as time (see API doc) 070 vin = transaction.getInputs().stream() 071 .map(input -> new Vin(txid, 072 input.getOutpoint().getIndex(), 073 input.getScriptSig().toString(), 074 input.getSequenceNumber()) 075 ) 076 .collect(Collectors.toList()); 077 vout = transaction.getOutputs().stream() 078 .map(output -> new Vout(output.getValue(), 079 output.getIndex(), 080 new ScriptPubKeyInfo(output.getScriptPubKey())) 081 ) 082 .collect(Collectors.toList()); 083 } 084 085 public String getHex() { 086 return hex; 087 } 088 089 public Sha256Hash getTxid() { 090 return txid; 091 } 092 093 public long getVersion() { 094 return version; 095 } 096 097 public LockTime getLockTime() { 098 return lockTime; 099 } 100 101 /** 102 * @return lock time 103 * @deprecated Use {@link #getLockTime()} 104 */ 105 @Deprecated 106 public long getLocktime() { 107 return getLockTime().rawValue(); 108 } 109 110 public List<Vin> getVin() { 111 return vin; 112 } 113 114 public List<Vout> getVout() { 115 return vout; 116 } 117 118 public Sha256Hash getBlockhash() { 119 return blockhash; 120 } 121 122 public int getConfirmations() { 123 return confirmations; 124 } 125 126 public Instant getTime() { 127 return time; 128 } 129 130 public Instant getBlocktime() { 131 return blocktime; 132 } 133 134 public static class VinList extends ArrayList<Vin> { 135 } 136 137 public static class VoutList extends ArrayList<Vout> { 138 } 139 140 public static class Vin { 141 public final Sha256Hash txid; 142 public final long vout; 143 public final Object scriptSig; 144 public final long sequence; 145 146 @JsonCreator 147 public Vin(@JsonProperty("txid") Sha256Hash txid, 148 @JsonProperty("vout") long vout, 149 @JsonProperty("scriptSig") Object scriptSig, 150 @JsonProperty("sequence") long sequence) { 151 this.txid = txid; 152 this.vout = vout; 153 this.scriptSig = scriptSig; 154 this.sequence = sequence; 155 } 156 157 public Sha256Hash getTxid() { 158 return txid; 159 } 160 161 public long getVout() { 162 return vout; 163 } 164 165 public Object getScriptSig() { 166 return scriptSig; 167 } 168 169 public long getSequence() { 170 return sequence; 171 } 172 } 173 174 public static class Vout { 175 public final Coin value; 176 public final int n; 177 public final ScriptPubKeyInfo scriptPubKey; 178 179 @JsonCreator 180 public Vout(@JsonProperty("value") Coin value, 181 @JsonProperty("n") int n, 182 @JsonProperty("scriptPubKey") ScriptPubKeyInfo scriptPubKey) { 183 this.value = value; 184 this.n = n; 185 this.scriptPubKey = scriptPubKey; 186 } 187 188 public Coin getValue() { 189 return value; 190 } 191 192 public int getN() { 193 return n; 194 } 195 196 public ScriptPubKeyInfo getScriptPubKey() { 197 return scriptPubKey; 198 } 199 } 200 201 public static class ScriptPubKeyInfo { 202 private final String asm; 203 private final String hex; 204 private final int reqSigs; 205 private final String type; 206 private final List<Address> addresses; 207 208 @JsonCreator 209 public ScriptPubKeyInfo(@JsonProperty("asm") String asm, 210 @JsonProperty("hex") String hex, 211 @JsonProperty("reqSigs") int reqSigs, 212 @JsonProperty("type") String type, 213 @JsonProperty("addresses") List<Address> addresses) { 214 this.asm = asm; 215 this.hex = hex; 216 this.reqSigs = reqSigs; 217 this.type = type; 218 this.addresses = addresses; 219 } 220 221 public ScriptPubKeyInfo(Script script) { 222 this.asm = script.toString(); 223 this.hex = HexUtil.bytesToHexString(script.program()); 224 this.reqSigs = -1; 225 this.type = "bitcoinj Script (not-fully-supported)"; 226 this.addresses = List.of(); 227 } 228 229 public String getAsm() { 230 return asm; 231 } 232 233 public String getHex() { 234 return hex; 235 } 236 237 public int getReqSigs() { 238 return reqSigs; 239 } 240 241 public String getType() { 242 return type; 243 } 244 245 public List<Address> getAddresses() { 246 return addresses; 247 } 248 } 249}