mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-07 06:44:16 +00:00
Refactor some Stored* classes that are worthless...
Specifically, this moves StoredTransaction to MemoryFullPrunedBlockStore and uses custom serialization for StoredTransactionOutput.
This commit is contained in:
parent
91cd289a5c
commit
a036b68aa2
@ -84,10 +84,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
||||
protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block block)
|
||||
throws BlockStoreException, VerificationException {
|
||||
StoredBlock newBlock = storedPrev.build(block);
|
||||
LinkedList<StoredTransaction> transactions = new LinkedList<StoredTransaction>();
|
||||
for (Transaction tx : block.transactions)
|
||||
transactions.add(new StoredTransaction(tx, newBlock.getHeight()));
|
||||
blockStore.put(newBlock, new StoredUndoableBlock(newBlock.getHeader().getHash(), transactions));
|
||||
blockStore.put(newBlock, new StoredUndoableBlock(newBlock.getHeader().getHash(), block.transactions));
|
||||
return newBlock;
|
||||
}
|
||||
|
||||
@ -287,14 +284,14 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
||||
}
|
||||
TransactionOutputChanges txOutChanges;
|
||||
try {
|
||||
List<StoredTransaction> transactions = block.getTransactions();
|
||||
List<Transaction> transactions = block.getTransactions();
|
||||
if (transactions != null) {
|
||||
LinkedList<StoredTransactionOutput> txOutsSpent = new LinkedList<StoredTransactionOutput>();
|
||||
LinkedList<StoredTransactionOutput> txOutsCreated = new LinkedList<StoredTransactionOutput>();
|
||||
long sigOps = 0;
|
||||
final boolean enforcePayToScriptHash = newBlock.getHeader().getTimeSeconds() >= params.BIP16_ENFORCE_TIME;
|
||||
if (!params.isCheckpoint(newBlock.getHeight())) {
|
||||
for(StoredTransaction tx : transactions) {
|
||||
for(Transaction tx : transactions) {
|
||||
Sha256Hash hash = tx.getHash();
|
||||
if (blockStore.hasUnspentOutputs(hash, tx.getOutputs().size()))
|
||||
throw new VerificationException("Block failed BIP30 test!");
|
||||
@ -306,7 +303,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
||||
if (scriptVerificationExecutor.isShutdown())
|
||||
scriptVerificationExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||
List<Future<VerificationException>> listScriptVerificationResults = new ArrayList<Future<VerificationException>>(transactions.size());
|
||||
for(final StoredTransaction tx : transactions) {
|
||||
for(final Transaction tx : transactions) {
|
||||
boolean isCoinBase = tx.isCoinBase();
|
||||
BigInteger valueIn = BigInteger.ZERO;
|
||||
BigInteger valueOut = BigInteger.ZERO;
|
||||
@ -340,7 +337,6 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
||||
// TODO: Find out the underlying issue and create a better work-around
|
||||
// TODO: Thoroughly test that this fixes the issue like the non-StoredBlock version does
|
||||
final int currentIndex = index;
|
||||
final Transaction txCache = new Transaction(params, tx);
|
||||
final Script scriptSig;
|
||||
try {
|
||||
scriptSig = in.getScriptSig();
|
||||
@ -356,7 +352,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
||||
FutureTask<VerificationException> future = new FutureTask<VerificationException>(new Callable<VerificationException>() {
|
||||
public VerificationException call() {
|
||||
try{
|
||||
scriptSig.correctlySpends(txCache, currentIndex, scriptPubKey, enforcePayToScriptHash);
|
||||
scriptSig.correctlySpends(tx, currentIndex, scriptPubKey, enforcePayToScriptHash);
|
||||
} catch (ScriptException e) {
|
||||
return new VerificationException("Error verifying script: " + e.getMessage());
|
||||
} catch (VerificationException e) {
|
||||
@ -372,7 +368,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
||||
}
|
||||
}
|
||||
Sha256Hash hash = tx.getHash();
|
||||
for (StoredTransactionOutput out : tx.getOutputs()) {
|
||||
for (TransactionOutput out : tx.getOutputs()) {
|
||||
valueOut = valueOut.add(out.getValue());
|
||||
StoredTransactionOutput newOut = new StoredTransactionOutput(hash, out.getIndex(), out.getValue(),
|
||||
newBlock.getHeight(), isCoinBase,
|
||||
|
@ -1,112 +0,0 @@
|
||||
/**
|
||||
* Copyright 2012 Matt Corallo.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.bitcoin.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
//TODO: Move this to MemoryFullPrunedBlockStore and use a different method for on-disk storage (bitcoin serialization?)
|
||||
/**
|
||||
* A StoredTransaction message contains the information necessary to check a transaction later (ie after a reorg).
|
||||
* It is used to avoid having to store the entire transaction when we only need its inputs+outputs.
|
||||
* Its only really useful for MemoryFullPrunedBlockStore, and should probably be moved there
|
||||
*/
|
||||
public class StoredTransaction implements Serializable {
|
||||
private static final long serialVersionUID = 6243881368122528323L;
|
||||
|
||||
/**
|
||||
* A transaction has some value and a script used for authenticating that the redeemer is allowed to spend
|
||||
* this output.
|
||||
*/
|
||||
private List<StoredTransactionOutput> outputs;
|
||||
private List<TransactionInput> inputs;
|
||||
private long version;
|
||||
private long lockTime;
|
||||
private Sha256Hash hash;
|
||||
|
||||
public StoredTransaction(Transaction tx, int height) {
|
||||
inputs = new LinkedList<TransactionInput>();
|
||||
outputs = new LinkedList<StoredTransactionOutput>();
|
||||
for (TransactionInput in : tx.getInputs())
|
||||
inputs.add(new TransactionInput(in.params, null, in.getScriptBytes(), in.getOutpoint()));
|
||||
for (TransactionOutput out : tx.getOutputs())
|
||||
outputs.add(new StoredTransactionOutput(null, out, height, tx.isCoinBase()));
|
||||
this.version = tx.getVersion();
|
||||
this.lockTime = tx.getLockTime();
|
||||
this.hash = tx.getHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* The lits of inputs in this transaction
|
||||
*/
|
||||
public List<TransactionInput> getInputs() {
|
||||
return inputs;
|
||||
}
|
||||
|
||||
/**
|
||||
* The lits of outputs in this transaction
|
||||
* Note that the hashes of all of these are null
|
||||
*/
|
||||
public List<StoredTransactionOutput> getOutputs() {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
/**
|
||||
* The hash of this stored transaction
|
||||
*/
|
||||
public Sha256Hash getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* The lockTime of the stored transaction
|
||||
*/
|
||||
public long getLockTime() {
|
||||
return lockTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of the stored transaction
|
||||
*/
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* A coinbase transaction is one that creates a new coin. They are the first transaction in each block and their
|
||||
* value is determined by a formula that all implementations of BitCoin share. In 2011 the value of a coinbase
|
||||
* transaction is 50 coins, but in future it will be less. A coinbase transaction is defined not only by its
|
||||
* position in a block but by the data in the inputs.
|
||||
*/
|
||||
public boolean isCoinBase() {
|
||||
return inputs.get(0).isCoinBase();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Stored Transaction: " + hash.toString();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return getHash().hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof StoredTransaction)) return false;
|
||||
return ((StoredTransaction) o).getHash().equals(this.getHash());
|
||||
}
|
||||
}
|
@ -16,6 +16,10 @@
|
||||
|
||||
package com.google.bitcoin.core;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
|
||||
@ -69,6 +73,35 @@ public class StoredTransactionOutput implements Serializable {
|
||||
this.scriptBytes = out.getScriptBytes();
|
||||
}
|
||||
|
||||
public StoredTransactionOutput(InputStream in) throws IOException {
|
||||
byte[] valueBytes = new byte[8];
|
||||
in.read(valueBytes, 0, 8);
|
||||
value = BigInteger.valueOf(Utils.readInt64(valueBytes, 0));
|
||||
|
||||
int scriptBytesLength = ((in.read() & 0xFF) << 0) |
|
||||
((in.read() & 0xFF) << 8) |
|
||||
((in.read() & 0xFF) << 16) |
|
||||
((in.read() & 0xFF) << 24);
|
||||
scriptBytes = new byte[scriptBytesLength];
|
||||
if (in.read(scriptBytes) != scriptBytesLength)
|
||||
throw new EOFException();
|
||||
|
||||
byte[] hashBytes = new byte[32];
|
||||
if (in.read(hashBytes) != 32)
|
||||
throw new EOFException();
|
||||
hash = new Sha256Hash(hashBytes);
|
||||
|
||||
byte[] indexBytes = new byte[4];
|
||||
if (in.read(indexBytes) != 4)
|
||||
throw new EOFException();
|
||||
index = Utils.readUint32(indexBytes, 0);
|
||||
|
||||
height = ((in.read() & 0xFF) << 0) |
|
||||
((in.read() & 0xFF) << 8) |
|
||||
((in.read() & 0xFF) << 16) |
|
||||
((in.read() & 0xFF) << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* The value which this Transaction output holds
|
||||
* @return the value
|
||||
@ -121,4 +154,22 @@ public class StoredTransactionOutput implements Serializable {
|
||||
return ((StoredTransactionOutput) o).getIndex() == this.getIndex() &&
|
||||
((StoredTransactionOutput) o).getHash().equals(this.getHash());
|
||||
}
|
||||
|
||||
public void serializeToStream(OutputStream bos) throws IOException {
|
||||
Utils.uint64ToByteStreamLE(value, bos);
|
||||
|
||||
bos.write((int) (0xFF & (scriptBytes.length >> 0)));
|
||||
bos.write((int) (0xFF & (scriptBytes.length >> 8)));
|
||||
bos.write((int) (0xFF & (scriptBytes.length >> 16)));
|
||||
bos.write((int) (0xFF & (scriptBytes.length >> 24)));
|
||||
bos.write(scriptBytes);
|
||||
|
||||
bos.write(hash.getBytes());
|
||||
Utils.uint32ToByteStreamLE(index, bos);
|
||||
|
||||
bos.write((int) (0xFF & (height >> 0)));
|
||||
bos.write((int) (0xFF & (height >> 8)));
|
||||
bos.write((int) (0xFF & (height >> 16)));
|
||||
bos.write((int) (0xFF & (height >> 24)));
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@ public class StoredUndoableBlock implements Serializable {
|
||||
|
||||
// Only one of either txOutChanges or transactions will be set
|
||||
private TransactionOutputChanges txOutChanges;
|
||||
private List<StoredTransaction> transactions;
|
||||
private List<Transaction> transactions;
|
||||
|
||||
public StoredUndoableBlock(Sha256Hash hash, TransactionOutputChanges txOutChanges) {
|
||||
this.blockHash = hash;
|
||||
@ -42,7 +42,7 @@ public class StoredUndoableBlock implements Serializable {
|
||||
this.txOutChanges = txOutChanges;
|
||||
}
|
||||
|
||||
public StoredUndoableBlock(Sha256Hash hash, List<StoredTransaction> transactions) {
|
||||
public StoredUndoableBlock(Sha256Hash hash, List<Transaction> transactions) {
|
||||
this.blockHash = hash;
|
||||
this.txOutChanges = null;
|
||||
this.transactions = transactions;
|
||||
@ -60,7 +60,7 @@ public class StoredUndoableBlock implements Serializable {
|
||||
* Get the full list of transactions if it is stored, otherwise null.
|
||||
* Only one of this and getTxOutChanges() will return a non-null value.
|
||||
*/
|
||||
public List<StoredTransaction> getTransactions() {
|
||||
public List<Transaction> getTransactions() {
|
||||
return transactions;
|
||||
}
|
||||
|
||||
|
@ -139,22 +139,6 @@ public class Transaction extends ChildMessage implements Serializable {
|
||||
throws ProtocolException {
|
||||
super(params, msg, 0, parent, parseLazy, parseRetain, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a transaction from the given StoredTransaction
|
||||
* This is unsafe in that editing some aspects of this transaction may edit the stored transaction.
|
||||
* Thus, this should only be used if the resulting transaction will only be used in a read-only manner.
|
||||
*/
|
||||
Transaction(NetworkParameters params, StoredTransaction tx) {
|
||||
super(params);
|
||||
this.version = tx.getVersion();
|
||||
this.lockTime = tx.getLockTime();
|
||||
this.inputs = new ArrayList<TransactionInput>(tx.getInputs());
|
||||
this.outputs = new ArrayList<TransactionOutput>(tx.getOutputs().size());
|
||||
for (StoredTransactionOutput output : tx.getOutputs()) {
|
||||
this.outputs.add(new TransactionOutput(params, this, output.getValue(), output.getScriptBytes()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transaction hash as you see them in the block explorer.
|
||||
|
@ -16,7 +16,10 @@
|
||||
|
||||
package com.google.bitcoin.core;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -25,9 +28,7 @@ import java.util.List;
|
||||
* It does contain outputs created that were spent later in the block, as those are needed for
|
||||
* BIP30 (no duplicate txid creation if the previous one was not fully spent prior to this block) verification.
|
||||
*/
|
||||
public class TransactionOutputChanges implements Serializable {
|
||||
private static final long serialVersionUID = -6169346729324181905L;
|
||||
|
||||
public class TransactionOutputChanges {
|
||||
public final List<StoredTransactionOutput> txOutsCreated;
|
||||
public final List<StoredTransactionOutput> txOutsSpent;
|
||||
|
||||
@ -35,4 +36,42 @@ public class TransactionOutputChanges implements Serializable {
|
||||
this.txOutsCreated = txOutsCreated;
|
||||
this.txOutsSpent = txOutsSpent;
|
||||
}
|
||||
|
||||
public TransactionOutputChanges(InputStream in) throws IOException {
|
||||
int numOutsCreated = ((in.read() & 0xFF) << 0) |
|
||||
((in.read() & 0xFF) << 8) |
|
||||
((in.read() & 0xFF) << 16) |
|
||||
((in.read() & 0xFF) << 24);
|
||||
txOutsCreated = new LinkedList<StoredTransactionOutput>();
|
||||
for (int i = 0; i < numOutsCreated; i++)
|
||||
txOutsCreated.add(new StoredTransactionOutput(in));
|
||||
|
||||
int numOutsSpent = ((in.read() & 0xFF) << 0) |
|
||||
((in.read() & 0xFF) << 8) |
|
||||
((in.read() & 0xFF) << 16) |
|
||||
((in.read() & 0xFF) << 24);
|
||||
txOutsSpent = new LinkedList<StoredTransactionOutput>();
|
||||
for (int i = 0; i < numOutsSpent; i++)
|
||||
txOutsSpent.add(new StoredTransactionOutput(in));
|
||||
}
|
||||
|
||||
public void serializeToStream(OutputStream bos) throws IOException {
|
||||
int numOutsCreated = txOutsCreated.size();
|
||||
bos.write((int) (0xFF & (numOutsCreated >> 0)));
|
||||
bos.write((int) (0xFF & (numOutsCreated >> 8)));
|
||||
bos.write((int) (0xFF & (numOutsCreated >> 16)));
|
||||
bos.write((int) (0xFF & (numOutsCreated >> 24)));
|
||||
for (StoredTransactionOutput output : txOutsCreated) {
|
||||
output.serializeToStream(bos);
|
||||
}
|
||||
|
||||
int numOutsSpent = txOutsSpent.size();
|
||||
bos.write((int) (0xFF & (numOutsSpent >> 0)));
|
||||
bos.write((int) (0xFF & (numOutsSpent >> 8)));
|
||||
bos.write((int) (0xFF & (numOutsSpent >> 16)));
|
||||
bos.write((int) (0xFF & (numOutsSpent >> 24)));
|
||||
for (StoredTransactionOutput output : txOutsSpent) {
|
||||
output.serializeToStream(bos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,10 +18,13 @@ package com.google.bitcoin.store;
|
||||
|
||||
import com.google.bitcoin.core.*;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.*;
|
||||
import java.util.LinkedList;
|
||||
@ -199,7 +202,7 @@ public class H2FullPrunedBlockStore implements FullPrunedBlockStore {
|
||||
StoredBlock storedGenesisHeader = new StoredBlock(params.genesisBlock.cloneAsHeader(), params.genesisBlock.getWork(), 0);
|
||||
// The coinbase in the genesis block is not spendable. This is because of how the reference client inits
|
||||
// its database - the genesis transaction isn't actually in the db so its spent flags can never be updated.
|
||||
List<StoredTransaction> genesisTransactions = Lists.newLinkedList();
|
||||
List<Transaction> genesisTransactions = Lists.newLinkedList();
|
||||
StoredUndoableBlock storedGenesis = new StoredUndoableBlock(params.genesisBlock.getHash(), genesisTransactions);
|
||||
put(storedGenesisHeader, storedGenesis);
|
||||
setChainHead(storedGenesisHeader);
|
||||
@ -339,15 +342,19 @@ public class H2FullPrunedBlockStore implements FullPrunedBlockStore {
|
||||
byte[] txOutChanges = null;
|
||||
try {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ObjectOutput out = new ObjectOutputStream(bos);
|
||||
if (undoableBlock.getTxOutChanges() != null) {
|
||||
out.writeObject(undoableBlock.getTxOutChanges());
|
||||
undoableBlock.getTxOutChanges().serializeToStream(bos);
|
||||
txOutChanges = bos.toByteArray();
|
||||
} else {
|
||||
out.writeObject(undoableBlock.getTransactions());
|
||||
int numTxn = undoableBlock.getTransactions().size();
|
||||
bos.write((int) (0xFF & (numTxn >> 0)));
|
||||
bos.write((int) (0xFF & (numTxn >> 8)));
|
||||
bos.write((int) (0xFF & (numTxn >> 16)));
|
||||
bos.write((int) (0xFF & (numTxn >> 24)));
|
||||
for (Transaction tx : undoableBlock.getTransactions())
|
||||
tx.bitcoinSerialize(bos);
|
||||
transactions = bos.toByteArray();
|
||||
}
|
||||
out.close();
|
||||
bos.close();
|
||||
} catch (IOException e) {
|
||||
throw new BlockStoreException(e);
|
||||
@ -436,7 +443,6 @@ public class H2FullPrunedBlockStore implements FullPrunedBlockStore {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public StoredUndoableBlock getUndoBlock(Sha256Hash hash) throws BlockStoreException {
|
||||
maybeConnect();
|
||||
PreparedStatement s = null;
|
||||
@ -456,14 +462,22 @@ public class H2FullPrunedBlockStore implements FullPrunedBlockStore {
|
||||
byte[] transactions = results.getBytes(2);
|
||||
StoredUndoableBlock block;
|
||||
if (txOutChanges == null) {
|
||||
Object transactionsObject = new ObjectInputStream(new ByteArrayInputStream(transactions)).readObject();
|
||||
if (!(((List<?>) transactionsObject).get(0) instanceof StoredTransaction))
|
||||
throw new BlockStoreException("Corrupted StoredUndoableBlock");
|
||||
block = new StoredUndoableBlock(hash, (List<StoredTransaction>) transactionsObject);
|
||||
int offset = 0;
|
||||
int numTxn = ((transactions[offset++] & 0xFF) << 0) |
|
||||
((transactions[offset++] & 0xFF) << 8) |
|
||||
((transactions[offset++] & 0xFF) << 16) |
|
||||
((transactions[offset++] & 0xFF) << 24);
|
||||
List<Transaction> transactionList = new LinkedList<Transaction>();
|
||||
for (int i = 0; i < numTxn; i++) {
|
||||
Transaction tx = new Transaction(params, transactions, offset);
|
||||
transactionList.add(tx);
|
||||
offset += tx.getMessageSize();
|
||||
}
|
||||
block = new StoredUndoableBlock(hash, transactionList);
|
||||
} else {
|
||||
ObjectInputStream obj = new ObjectInputStream(new ByteArrayInputStream(txOutChanges));
|
||||
Object transactionsObject = obj.readObject();
|
||||
block = new StoredUndoableBlock(hash, (TransactionOutputChanges) transactionsObject);
|
||||
TransactionOutputChanges outChangesObject =
|
||||
new TransactionOutputChanges(new ByteArrayInputStream(txOutChanges));
|
||||
block = new StoredUndoableBlock(hash, outChangesObject);
|
||||
}
|
||||
return block;
|
||||
} catch (SQLException ex) {
|
||||
@ -474,7 +488,7 @@ public class H2FullPrunedBlockStore implements FullPrunedBlockStore {
|
||||
} catch (ClassCastException e) {
|
||||
// Corrupted database.
|
||||
throw new BlockStoreException(e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
} catch (ProtocolException e) {
|
||||
// Corrupted database.
|
||||
throw new BlockStoreException(e);
|
||||
} catch (IOException e) {
|
||||
|
@ -25,6 +25,95 @@ import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* A StoredTransaction message contains the information necessary to check a transaction later (ie after a reorg).
|
||||
* It is used to avoid having to store the entire transaction when we only need its inputs+outputs.
|
||||
*/
|
||||
class StoredTransaction implements Serializable {
|
||||
private static final long serialVersionUID = 6243881368122528323L;
|
||||
|
||||
/**
|
||||
* A transaction has some value and a script used for authenticating that the redeemer is allowed to spend
|
||||
* this output.
|
||||
*/
|
||||
private List<StoredTransactionOutput> outputs;
|
||||
private List<TransactionInput> inputs;
|
||||
private long version;
|
||||
private long lockTime;
|
||||
private Sha256Hash hash;
|
||||
|
||||
public StoredTransaction(NetworkParameters params, Transaction tx, int height) {
|
||||
inputs = new LinkedList<TransactionInput>();
|
||||
outputs = new LinkedList<StoredTransactionOutput>();
|
||||
for (TransactionInput in : tx.getInputs())
|
||||
inputs.add(new TransactionInput(params, null, in.getScriptBytes(), in.getOutpoint()));
|
||||
for (TransactionOutput out : tx.getOutputs())
|
||||
outputs.add(new StoredTransactionOutput(null, out, height, tx.isCoinBase()));
|
||||
this.version = tx.getVersion();
|
||||
this.lockTime = tx.getLockTime();
|
||||
this.hash = tx.getHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* The lits of inputs in this transaction
|
||||
*/
|
||||
public List<TransactionInput> getInputs() {
|
||||
return inputs;
|
||||
}
|
||||
|
||||
/**
|
||||
* The lits of outputs in this transaction
|
||||
* Note that the hashes of all of these are null
|
||||
*/
|
||||
public List<StoredTransactionOutput> getOutputs() {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
/**
|
||||
* The hash of this stored transaction
|
||||
*/
|
||||
public Sha256Hash getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* The lockTime of the stored transaction
|
||||
*/
|
||||
public long getLockTime() {
|
||||
return lockTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of the stored transaction
|
||||
*/
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* A coinbase transaction is one that creates a new coin. They are the first transaction in each block and their
|
||||
* value is determined by a formula that all implementations of BitCoin share. In 2011 the value of a coinbase
|
||||
* transaction is 50 coins, but in future it will be less. A coinbase transaction is defined not only by its
|
||||
* position in a block but by the data in the inputs.
|
||||
*/
|
||||
public boolean isCoinBase() {
|
||||
return inputs.get(0).isCoinBase();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Stored Transaction: " + hash.toString();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return getHash().hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof StoredTransaction)) return false;
|
||||
return ((StoredTransaction) o).getHash().equals(this.getHash());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used as a key for memory map (to avoid having to think about NetworkParameters,
|
||||
* which is required for {@link TransactionOutPoint}
|
||||
@ -240,7 +329,7 @@ public class MemoryFullPrunedBlockStore implements FullPrunedBlockStore {
|
||||
try {
|
||||
StoredBlock storedGenesisHeader = new StoredBlock(params.genesisBlock.cloneAsHeader(), params.genesisBlock.getWork(), 0);
|
||||
// The coinbase in the genesis block is not spendable
|
||||
List<StoredTransaction> genesisTransactions = Lists.newLinkedList();
|
||||
List<Transaction> genesisTransactions = Lists.newLinkedList();
|
||||
StoredUndoableBlock storedGenesis = new StoredUndoableBlock(params.genesisBlock.getHash(), genesisTransactions);
|
||||
put(storedGenesisHeader, storedGenesis);
|
||||
setChainHead(storedGenesisHeader);
|
||||
|
Loading…
Reference in New Issue
Block a user