mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-07 06:44:16 +00:00
Add a few Storage classes which avoid storing unnecessary data.
Specifically, this adds: * StoredTransaction, which avoid having to store the entire transaction when we only need its inputs+outputs. * StoredTransactionOutput, which avoids having to store the entire parentTransaction just to get the hash and index. * TransactionOutputChanges, which is used to store two lists of StoredTransactionOutputs, one for the created set and one for the spent set. * StoredUndoableBlock, which can store either only TransactionOutputChanges or only StoredTransactions so that the block can be more easily connected/disconnected at will.
This commit is contained in:
parent
8a4c34edd0
commit
b4215e8b01
@ -840,7 +840,8 @@ public class Block extends Message {
|
||||
// Here we will do things a bit differently so a new address isn't needed every time. We'll put a simple
|
||||
// counter in the scriptSig so every transaction has a different hash.
|
||||
coinbase.addInput(new TransactionInput(params, coinbase, new byte[]{(byte) txCounter++}));
|
||||
coinbase.addOutput(new TransactionOutput(params, coinbase, Script.createOutputScript(pubKeyTo)));
|
||||
coinbase.addOutput(new TransactionOutput(params, coinbase, Script.createOutputScript(pubKeyTo),
|
||||
Utils.toNanoCoins(50, 0)));
|
||||
transactions.add(coinbase);
|
||||
coinbase.setParent(this);
|
||||
coinbase.length = coinbase.bitcoinSerialize().length;
|
||||
|
@ -128,7 +128,7 @@ public class NetworkParameters implements Serializable {
|
||||
Script.writeBytes(scriptPubKeyBytes, Hex.decode
|
||||
("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"));
|
||||
scriptPubKeyBytes.write(Script.OP_CHECKSIG);
|
||||
t.addOutput(new TransactionOutput(n, t, scriptPubKeyBytes.toByteArray()));
|
||||
t.addOutput(new TransactionOutput(n, t, scriptPubKeyBytes.toByteArray(), Utils.toNanoCoins(50, 0)));
|
||||
} catch (Exception e) {
|
||||
// Cannot happen.
|
||||
throw new RuntimeException(e);
|
||||
|
@ -0,0 +1,112 @@
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* 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.math.BigInteger;
|
||||
|
||||
/**
|
||||
* A StoredTransactionOutput message contains the information necessary to check a spending transaction.
|
||||
* It avoids having to store the entire parentTransaction just to get the hash and index.
|
||||
* Its only really useful for MemoryFullPrunedBlockStore, and should probably be moved there
|
||||
*/
|
||||
public class StoredTransactionOutput implements Serializable {
|
||||
private static final long serialVersionUID = -8744924157056340509L;
|
||||
|
||||
/**
|
||||
* A transaction output has some value and a script used for authenticating that the redeemer is allowed to spend
|
||||
* this output.
|
||||
*/
|
||||
private BigInteger value;
|
||||
private byte[] scriptBytes;
|
||||
|
||||
/** Hash of the transaction to which we refer. */
|
||||
private Sha256Hash hash;
|
||||
/** Which output of that transaction we are talking about. */
|
||||
private long index;
|
||||
|
||||
/** arbitrary value lower than -{@link NetworkParameters.spendableCoinbaseDepth}
|
||||
* (not too low to get overflows when we do blockHeight - NONCOINBASE_HEIGHT, though) */
|
||||
private static final int NONCOINBASE_HEIGHT = -200;
|
||||
/** The height of the creating block (for coinbases, NONCOINBASE_HEIGHT otherwise) */
|
||||
private int height;
|
||||
|
||||
/**
|
||||
* Creates a stored transaction output
|
||||
* @param hash the hash of the containing transaction
|
||||
* @param index the outpoint
|
||||
* @param value the value available
|
||||
* @param height the height this output was created in
|
||||
* @param scriptBytes
|
||||
*/
|
||||
public StoredTransactionOutput(Sha256Hash hash, long index, BigInteger value, int height, boolean isCoinbase, byte[] scriptBytes) {
|
||||
this.hash = hash;
|
||||
this.index = index;
|
||||
this.value = value;
|
||||
this.height = isCoinbase ? height : NONCOINBASE_HEIGHT;
|
||||
this.scriptBytes = scriptBytes;
|
||||
}
|
||||
|
||||
public StoredTransactionOutput(Sha256Hash hash, TransactionOutput out, int height, boolean isCoinbase) {
|
||||
this.hash = hash;
|
||||
this.index = out.getIndex();
|
||||
this.value = out.getValue();
|
||||
this.height = isCoinbase ? height : NONCOINBASE_HEIGHT;
|
||||
this.scriptBytes = out.getScriptBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* The value which this Transaction output holds
|
||||
* @return the value
|
||||
*/
|
||||
public BigInteger getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The backing script bytes which can be turned into a Script object.
|
||||
* @return the scriptBytes
|
||||
*/
|
||||
public byte[] getScriptBytes() {
|
||||
return scriptBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* The hash of the transaction which holds this output
|
||||
* @return the hash
|
||||
*/
|
||||
public Sha256Hash getHash() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* The index of this output in the transaction which holds it
|
||||
* @return the index
|
||||
*/
|
||||
public long getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the height of the block that created this output (or -1 if this output was not created by a coinbase)
|
||||
*/
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("Stored TxOut of %s (%s:%l)", Utils.bitcoinValueToFriendlyString(value), hash.toString(), index);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return hash.hashCode() + (int)index;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof StoredTransactionOutput)) return false;
|
||||
return ((StoredTransactionOutput) o).getIndex() == this.getIndex() &&
|
||||
((StoredTransactionOutput) o).getHash().equals(this.getHash());
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright 2011 Google Inc.
|
||||
* 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.List;
|
||||
|
||||
/**
|
||||
* Contains minimal data neccessary to disconnect/connect the transactions
|
||||
* in the stored block at will. Can either store the full set of
|
||||
* transactions (if the inputs for the block have not been tested to work)
|
||||
* or the set of transaction outputs created/destroyed when the block is
|
||||
* connected.
|
||||
*/
|
||||
public class StoredUndoableBlock implements Serializable {
|
||||
private static final long serialVersionUID = 5127353027086786117L;
|
||||
|
||||
Sha256Hash blockHash;
|
||||
|
||||
// Only one of either txOutChanges or transactions will be set
|
||||
private TransactionOutputChanges txOutChanges;
|
||||
private List<StoredTransaction> transactions;
|
||||
|
||||
public StoredUndoableBlock(Sha256Hash hash, TransactionOutputChanges txOutChanges) {
|
||||
this.blockHash = hash;
|
||||
this.transactions = null;
|
||||
this.txOutChanges = txOutChanges;
|
||||
}
|
||||
|
||||
public StoredUndoableBlock(Sha256Hash hash, List<StoredTransaction> transactions) {
|
||||
this.blockHash = hash;
|
||||
this.txOutChanges = null;
|
||||
this.transactions = transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the transaction output changes if they have been calculated, otherwise null.
|
||||
* Only one of this and getTransactions() will return a non-null value.
|
||||
*/
|
||||
public TransactionOutputChanges getTxOutChanges() {
|
||||
return txOutChanges;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
return transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hash of the represented block
|
||||
*/
|
||||
public Sha256Hash getHash() {
|
||||
return blockHash;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return blockHash.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof StoredUndoableBlock)) return false;
|
||||
return ((StoredUndoableBlock)o).getHash().equals(this.getHash());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Undoable Block " + blockHash.toString();
|
||||
}
|
||||
}
|
@ -137,6 +137,22 @@ public class Transaction extends ChildMessage implements Serializable {
|
||||
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.getScriptBytes(), output.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transaction hash as you see them in the block explorer.
|
||||
*/
|
||||
|
@ -114,10 +114,10 @@ public class TransactionOutput extends ChildMessage implements Serializable {
|
||||
/**
|
||||
* Used only in creation of the genesis blocks and in unit tests.
|
||||
*/
|
||||
TransactionOutput(NetworkParameters params, Transaction parent, byte[] scriptBytes) {
|
||||
TransactionOutput(NetworkParameters params, Transaction parent, byte[] scriptBytes, BigInteger value) {
|
||||
super(params);
|
||||
this.scriptBytes = scriptBytes;
|
||||
this.value = Utils.toNanoCoins(50, 0);
|
||||
this.value = value;
|
||||
parentTransaction = parent;
|
||||
availableForSpending = true;
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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.List;
|
||||
|
||||
/**
|
||||
* TransactionOutputChanges is used as a return value for BlockChainBase.connectInputs.
|
||||
* It contains the full list of transaction outputs created and spent in a block.
|
||||
* 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 final List<StoredTransactionOutput> txOutsCreated;
|
||||
public final List<StoredTransactionOutput> txOutsSpent;
|
||||
|
||||
public TransactionOutputChanges(List<StoredTransactionOutput> txOutsCreated, List<StoredTransactionOutput> txOutsSpent) {
|
||||
this.txOutsCreated = txOutsCreated;
|
||||
this.txOutsSpent = txOutsSpent;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user