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
|
// 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.
|
// counter in the scriptSig so every transaction has a different hash.
|
||||||
coinbase.addInput(new TransactionInput(params, coinbase, new byte[]{(byte) txCounter++}));
|
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);
|
transactions.add(coinbase);
|
||||||
coinbase.setParent(this);
|
coinbase.setParent(this);
|
||||||
coinbase.length = coinbase.bitcoinSerialize().length;
|
coinbase.length = coinbase.bitcoinSerialize().length;
|
||||||
|
@ -128,7 +128,7 @@ public class NetworkParameters implements Serializable {
|
|||||||
Script.writeBytes(scriptPubKeyBytes, Hex.decode
|
Script.writeBytes(scriptPubKeyBytes, Hex.decode
|
||||||
("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"));
|
("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"));
|
||||||
scriptPubKeyBytes.write(Script.OP_CHECKSIG);
|
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) {
|
} catch (Exception e) {
|
||||||
// Cannot happen.
|
// Cannot happen.
|
||||||
throw new RuntimeException(e);
|
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);
|
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.
|
* 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.
|
* 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);
|
super(params);
|
||||||
this.scriptBytes = scriptBytes;
|
this.scriptBytes = scriptBytes;
|
||||||
this.value = Utils.toNanoCoins(50, 0);
|
this.value = value;
|
||||||
parentTransaction = parent;
|
parentTransaction = parent;
|
||||||
availableForSpending = true;
|
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