mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-01-30 23:02:15 +00:00
Label transactions with their source (network, wallet, other, etc).
This will be used to allow spending of unconfirmed change.
This commit is contained in:
parent
3b7a494a37
commit
988641a5f7
@ -18,7 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Notes:
|
/* Notes:
|
||||||
* - Endianness: All byte arrays that represent numbers (such as hashes and private keys) are Big Endian (a.k.a. network order)
|
* - Endianness: All byte arrays that represent numbers (such as hashes and private keys) are Big Endian
|
||||||
|
* - To regenerate after editing, run mvn clean package -DupdateProtobuf
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package wallet;
|
package wallet;
|
||||||
@ -115,6 +116,18 @@ message TransactionConfidence {
|
|||||||
optional int64 work_done = 5;
|
optional int64 work_done = 5;
|
||||||
|
|
||||||
repeated PeerAddress broadcast_by = 6;
|
repeated PeerAddress broadcast_by = 6;
|
||||||
|
|
||||||
|
// Where did we get this transaction from? Knowing the source may help us to risk analyze pending transactions.
|
||||||
|
enum Source {
|
||||||
|
SOURCE_UNKNOWN = 0; // We don't know where it came from, or this is a wallet from the future.
|
||||||
|
SOURCE_NETWORK = 1; // We received it from a network broadcast. This is the normal way to get payments.
|
||||||
|
SOURCE_SELF = 2; // We made it ourselves, so we know it should be valid.
|
||||||
|
// In future:
|
||||||
|
// - direct from trusted counterparty, eg via bluetooth/wifi direct
|
||||||
|
// - direct from untrusted counterparty
|
||||||
|
// - from a wallet that uses trusted computing/secure hardware that won't create double spends
|
||||||
|
}
|
||||||
|
optional Source source = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A bitcoin transaction */
|
/** A bitcoin transaction */
|
||||||
|
@ -185,6 +185,8 @@ public class Block extends Message {
|
|||||||
transactions = new ArrayList<Transaction>(numTransactions);
|
transactions = new ArrayList<Transaction>(numTransactions);
|
||||||
for (int i = 0; i < numTransactions; i++) {
|
for (int i = 0; i < numTransactions; i++) {
|
||||||
Transaction tx = new Transaction(params, bytes, cursor, this, parseLazy, parseRetain, UNKNOWN_LENGTH);
|
Transaction tx = new Transaction(params, bytes, cursor, this, parseLazy, parseRetain, UNKNOWN_LENGTH);
|
||||||
|
// Label the transaction as coming from the P2P network, so code that cares where we first saw it knows.
|
||||||
|
tx.getConfidence().setSource(TransactionConfidence.Source.NETWORK);
|
||||||
transactions.add(tx);
|
transactions.add(tx);
|
||||||
cursor += tx.getMessageSize();
|
cursor += tx.getMessageSize();
|
||||||
optimalEncodingMessageSize += tx.getOptimalEncodingMessageSize();
|
optimalEncodingMessageSize += tx.getOptimalEncodingMessageSize();
|
||||||
|
@ -416,6 +416,9 @@ public class Peer {
|
|||||||
tx = memoryPool.seen(tx, getAddress());
|
tx = memoryPool.seen(tx, getAddress());
|
||||||
}
|
}
|
||||||
final Transaction fTx = tx;
|
final Transaction fTx = tx;
|
||||||
|
// Label the transaction as coming in from the P2P network (as opposed to being created by us, direct import,
|
||||||
|
// etc). This helps the wallet decide how to risk analyze it later.
|
||||||
|
fTx.getConfidence().setSource(TransactionConfidence.Source.NETWORK);
|
||||||
if (maybeHandleRequestedData(fTx)) {
|
if (maybeHandleRequestedData(fTx)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -67,43 +67,11 @@ public class TransactionConfidence implements Serializable {
|
|||||||
// Lazily created listeners array.
|
// Lazily created listeners array.
|
||||||
private transient ArrayList<Listener> listeners;
|
private transient ArrayList<Listener> listeners;
|
||||||
|
|
||||||
/**
|
// The depth of the transaction on the best chain in blocks. An unconfirmed block has depth 0.
|
||||||
* The depth of the transaction on the best chain in blocks. An unconfirmed block has depth 0, after one confirmation
|
|
||||||
* its depth is 1.
|
|
||||||
*/
|
|
||||||
private int depth;
|
private int depth;
|
||||||
|
// The cumulative work done for the blocks that bury this transaction.
|
||||||
/**
|
|
||||||
* The cumulative work done for the blocks that bury this transaction. BigInteger.ZERO if the transaction is not
|
|
||||||
* on the best chain.
|
|
||||||
*/
|
|
||||||
private BigInteger workDone = BigInteger.ZERO;
|
private BigInteger workDone = BigInteger.ZERO;
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Adds an event listener that will be run when this confidence object is updated. The listener will be locked and
|
|
||||||
* is likely to be invoked on a peer thread.</p>
|
|
||||||
*
|
|
||||||
* <p>Note that this is NOT called when every block arrives. Instead it is called when the transaction
|
|
||||||
* transitions between confidence states, ie, from not being seen in the chain to being seen (not necessarily in
|
|
||||||
* the best chain). If you want to know when the transaction gets buried under another block, implement a
|
|
||||||
* {@link BlockChainListener}, attach it to a {@link BlockChain} and then use the getters on the
|
|
||||||
* confidence object to determine the new depth.</p>
|
|
||||||
*/
|
|
||||||
public synchronized void addEventListener(Listener listener) {
|
|
||||||
Preconditions.checkNotNull(listener);
|
|
||||||
if (listeners == null)
|
|
||||||
listeners = new ArrayList<Listener>(2);
|
|
||||||
// Dedupe registrations. This makes the wallet code simpler.
|
|
||||||
if (!listeners.contains(listener))
|
|
||||||
listeners.add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void removeEventListener(Listener listener) {
|
|
||||||
Preconditions.checkNotNull(listener);
|
|
||||||
Preconditions.checkNotNull(listeners);
|
|
||||||
listeners.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Describes the state of the transaction in general terms. Properties can be read to learn specifics. */
|
/** Describes the state of the transaction in general terms. Properties can be read to learn specifics. */
|
||||||
public enum ConfidenceType {
|
public enum ConfidenceType {
|
||||||
/** If BUILDING, then the transaction is included in the best chain and your confidence in it is increasing. */
|
/** If BUILDING, then the transaction is included in the best chain and your confidence in it is increasing. */
|
||||||
@ -161,6 +129,32 @@ public class TransactionConfidence implements Serializable {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private ConfidenceType confidenceType = ConfidenceType.UNKNOWN;
|
||||||
|
private int appearedAtChainHeight = -1;
|
||||||
|
// The transaction that double spent this one, if any.
|
||||||
|
private Transaction overridingTransaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about where the transaction was first seen (network, sent direct from peer, created by ourselves).
|
||||||
|
* Useful for risk analyzing pending transactions. Probably not that useful after a tx is included in the chain,
|
||||||
|
* unless re-org double spends start happening frequently.
|
||||||
|
*/
|
||||||
|
public enum Source {
|
||||||
|
/** We don't know where the transaction came from. */
|
||||||
|
UNKNOWN,
|
||||||
|
/** We got this transaction from a network peer. */
|
||||||
|
NETWORK,
|
||||||
|
/** This transaction was created by our own wallet, so we know it's not a double spend. */
|
||||||
|
SELF
|
||||||
|
}
|
||||||
|
private Source source = Source.UNKNOWN;
|
||||||
|
|
||||||
|
public TransactionConfidence(Transaction tx) {
|
||||||
|
// Assume a default number of peers for our set.
|
||||||
|
broadcastBy = new CopyOnWriteArrayList<PeerAddress>();
|
||||||
|
transaction = tx;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>A confidence listener is informed when the level of {@link TransactionConfidence} is updated by something, like
|
* <p>A confidence listener is informed when the level of {@link TransactionConfidence} is updated by something, like
|
||||||
* for example a {@link Wallet}. You can add listeners to update your user interface or manage your order tracking
|
* for example a {@link Wallet}. You can add listeners to update your user interface or manage your order tracking
|
||||||
@ -174,14 +168,29 @@ public class TransactionConfidence implements Serializable {
|
|||||||
public void onConfidenceChanged(Transaction tx);
|
public void onConfidenceChanged(Transaction tx);
|
||||||
};
|
};
|
||||||
|
|
||||||
private ConfidenceType confidenceType = ConfidenceType.UNKNOWN;
|
/**
|
||||||
private int appearedAtChainHeight = -1;
|
* <p>Adds an event listener that will be run when this confidence object is updated. The listener will be locked and
|
||||||
private Transaction overridingTransaction;
|
* is likely to be invoked on a peer thread.</p>
|
||||||
|
*
|
||||||
|
* <p>Note that this is NOT called when every block arrives. Instead it is called when the transaction
|
||||||
|
* transitions between confidence states, ie, from not being seen in the chain to being seen (not necessarily in
|
||||||
|
* the best chain). If you want to know when the transaction gets buried under another block, implement a
|
||||||
|
* {@link BlockChainListener}, attach it to a {@link BlockChain} and then use the getters on the
|
||||||
|
* confidence object to determine the new depth.</p>
|
||||||
|
*/
|
||||||
|
public synchronized void addEventListener(Listener listener) {
|
||||||
|
Preconditions.checkNotNull(listener);
|
||||||
|
if (listeners == null)
|
||||||
|
listeners = new ArrayList<Listener>(2);
|
||||||
|
// Dedupe registrations. This makes the wallet code simpler.
|
||||||
|
if (!listeners.contains(listener))
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
public TransactionConfidence(Transaction tx) {
|
public synchronized void removeEventListener(Listener listener) {
|
||||||
// Assume a default number of peers for our set.
|
Preconditions.checkNotNull(listener);
|
||||||
broadcastBy = new CopyOnWriteArrayList<PeerAddress>();
|
Preconditions.checkNotNull(listeners);
|
||||||
transaction = tx;
|
listeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -403,4 +412,24 @@ public class TransactionConfidence implements Serializable {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source of a transaction tries to identify where it came from originally. For instance, did we download it
|
||||||
|
* from the peer to peer network, or make it ourselves, or receive it via Bluetooth, or import it from another app,
|
||||||
|
* and so on. This information is useful for {@link Wallet.CoinSelector} implementations to risk analyze
|
||||||
|
* transactions and decide when to spend them.
|
||||||
|
*/
|
||||||
|
public synchronized Source getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source of a transaction tries to identify where it came from originally. For instance, did we download it
|
||||||
|
* from the peer to peer network, or make it ourselves, or receive it via Bluetooth, or import it from another app,
|
||||||
|
* and so on. This information is useful for {@link Wallet.CoinSelector} implementations to risk analyze
|
||||||
|
* transactions and decide when to spend them.
|
||||||
|
*/
|
||||||
|
public synchronized void setSource(Source source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -705,6 +705,9 @@ public class Wallet implements Serializable, BlockChainListener {
|
|||||||
" and sends us %s BTC", tx.getHashAsString(), Utils.bitcoinValueToFriendlyString(valueSentFromMe),
|
" and sends us %s BTC", tx.getHashAsString(), Utils.bitcoinValueToFriendlyString(valueSentFromMe),
|
||||||
Utils.bitcoinValueToFriendlyString(valueSentToMe)));
|
Utils.bitcoinValueToFriendlyString(valueSentToMe)));
|
||||||
}
|
}
|
||||||
|
if (tx.getConfidence().getSource().equals(TransactionConfidence.Source.UNKNOWN)) {
|
||||||
|
log.warn("Wallet received transaction with an unknown source. Consider tagging tx!");
|
||||||
|
}
|
||||||
// Mark the tx as having been seen but is not yet in the chain. This will normally have been done already by
|
// Mark the tx as having been seen but is not yet in the chain. This will normally have been done already by
|
||||||
// the Peer before we got to this point, but in some cases (unit tests, other sources of transactions) it may
|
// the Peer before we got to this point, but in some cases (unit tests, other sources of transactions) it may
|
||||||
// have been missed out.
|
// have been missed out.
|
||||||
@ -1662,6 +1665,11 @@ public class Wallet implements Serializable, BlockChainListener {
|
|||||||
// happen, if it does it means the wallet has got into an inconsistent state.
|
// happen, if it does it means the wallet has got into an inconsistent state.
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Label the transaction as being self created. We can use this later to spend its change output even before
|
||||||
|
// the transaction is confirmed.
|
||||||
|
req.tx.getConfidence().setSource(TransactionConfidence.Source.SELF);
|
||||||
|
|
||||||
req.completed = true;
|
req.completed = true;
|
||||||
log.info(" completed {}", req.tx.getHashAsString());
|
log.info(" completed {}", req.tx.getHashAsString());
|
||||||
return true;
|
return true;
|
||||||
|
@ -213,6 +213,15 @@ public class WalletProtobufSerializer {
|
|||||||
Sha256Hash overridingHash = confidence.getOverridingTransaction().getHash();
|
Sha256Hash overridingHash = confidence.getOverridingTransaction().getHash();
|
||||||
confidenceBuilder.setOverridingTransaction(hashToByteString(overridingHash));
|
confidenceBuilder.setOverridingTransaction(hashToByteString(overridingHash));
|
||||||
}
|
}
|
||||||
|
TransactionConfidence.Source source = confidence.getSource();
|
||||||
|
switch (source) {
|
||||||
|
case SELF: confidenceBuilder.setSource(Protos.TransactionConfidence.Source.SOURCE_SELF); break;
|
||||||
|
case NETWORK: confidenceBuilder.setSource(Protos.TransactionConfidence.Source.SOURCE_NETWORK); break;
|
||||||
|
case UNKNOWN:
|
||||||
|
// Fall through.
|
||||||
|
default:
|
||||||
|
confidenceBuilder.setSource(Protos.TransactionConfidence.Source.SOURCE_UNKNOWN); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (ListIterator<PeerAddress> it = confidence.getBroadcastBy(); it.hasNext();) {
|
for (ListIterator<PeerAddress> it = confidence.getBroadcastBy(); it.hasNext();) {
|
||||||
PeerAddress address = it.next();
|
PeerAddress address = it.next();
|
||||||
@ -423,5 +432,12 @@ public class WalletProtobufSerializer {
|
|||||||
address.setServices(BigInteger.valueOf(proto.getServices()));
|
address.setServices(BigInteger.valueOf(proto.getServices()));
|
||||||
confidence.markBroadcastBy(address);
|
confidence.markBroadcastBy(address);
|
||||||
}
|
}
|
||||||
|
switch (confidenceProto.getSource()) {
|
||||||
|
case SOURCE_SELF: confidence.setSource(TransactionConfidence.Source.SELF); break;
|
||||||
|
case SOURCE_NETWORK: confidence.setSource(TransactionConfidence.Source.NETWORK); break;
|
||||||
|
case SOURCE_UNKNOWN:
|
||||||
|
// Fall through.
|
||||||
|
default: confidence.setSource(TransactionConfidence.Source.UNKNOWN); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2281,6 +2281,10 @@ public final class Protos {
|
|||||||
getBroadcastByOrBuilderList();
|
getBroadcastByOrBuilderList();
|
||||||
org.bitcoinj.wallet.Protos.PeerAddressOrBuilder getBroadcastByOrBuilder(
|
org.bitcoinj.wallet.Protos.PeerAddressOrBuilder getBroadcastByOrBuilder(
|
||||||
int index);
|
int index);
|
||||||
|
|
||||||
|
// optional .wallet.TransactionConfidence.Source source = 7;
|
||||||
|
boolean hasSource();
|
||||||
|
org.bitcoinj.wallet.Protos.TransactionConfidence.Source getSource();
|
||||||
}
|
}
|
||||||
public static final class TransactionConfidence extends
|
public static final class TransactionConfidence extends
|
||||||
com.google.protobuf.GeneratedMessage
|
com.google.protobuf.GeneratedMessage
|
||||||
@ -2388,6 +2392,78 @@ public final class Protos {
|
|||||||
// @@protoc_insertion_point(enum_scope:wallet.TransactionConfidence.Type)
|
// @@protoc_insertion_point(enum_scope:wallet.TransactionConfidence.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Source
|
||||||
|
implements com.google.protobuf.ProtocolMessageEnum {
|
||||||
|
SOURCE_UNKNOWN(0, 0),
|
||||||
|
SOURCE_NETWORK(1, 1),
|
||||||
|
SOURCE_SELF(2, 2),
|
||||||
|
;
|
||||||
|
|
||||||
|
public static final int SOURCE_UNKNOWN_VALUE = 0;
|
||||||
|
public static final int SOURCE_NETWORK_VALUE = 1;
|
||||||
|
public static final int SOURCE_SELF_VALUE = 2;
|
||||||
|
|
||||||
|
|
||||||
|
public final int getNumber() { return value; }
|
||||||
|
|
||||||
|
public static Source valueOf(int value) {
|
||||||
|
switch (value) {
|
||||||
|
case 0: return SOURCE_UNKNOWN;
|
||||||
|
case 1: return SOURCE_NETWORK;
|
||||||
|
case 2: return SOURCE_SELF;
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static com.google.protobuf.Internal.EnumLiteMap<Source>
|
||||||
|
internalGetValueMap() {
|
||||||
|
return internalValueMap;
|
||||||
|
}
|
||||||
|
private static com.google.protobuf.Internal.EnumLiteMap<Source>
|
||||||
|
internalValueMap =
|
||||||
|
new com.google.protobuf.Internal.EnumLiteMap<Source>() {
|
||||||
|
public Source findValueByNumber(int number) {
|
||||||
|
return Source.valueOf(number);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public final com.google.protobuf.Descriptors.EnumValueDescriptor
|
||||||
|
getValueDescriptor() {
|
||||||
|
return getDescriptor().getValues().get(index);
|
||||||
|
}
|
||||||
|
public final com.google.protobuf.Descriptors.EnumDescriptor
|
||||||
|
getDescriptorForType() {
|
||||||
|
return getDescriptor();
|
||||||
|
}
|
||||||
|
public static final com.google.protobuf.Descriptors.EnumDescriptor
|
||||||
|
getDescriptor() {
|
||||||
|
return org.bitcoinj.wallet.Protos.TransactionConfidence.getDescriptor().getEnumTypes().get(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Source[] VALUES = {
|
||||||
|
SOURCE_UNKNOWN, SOURCE_NETWORK, SOURCE_SELF,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Source valueOf(
|
||||||
|
com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
|
||||||
|
if (desc.getType() != getDescriptor()) {
|
||||||
|
throw new java.lang.IllegalArgumentException(
|
||||||
|
"EnumValueDescriptor is not for this type.");
|
||||||
|
}
|
||||||
|
return VALUES[desc.getIndex()];
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int index;
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
private Source(int index, int value) {
|
||||||
|
this.index = index;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@protoc_insertion_point(enum_scope:wallet.TransactionConfidence.Source)
|
||||||
|
}
|
||||||
|
|
||||||
private int bitField0_;
|
private int bitField0_;
|
||||||
// optional .wallet.TransactionConfidence.Type type = 1;
|
// optional .wallet.TransactionConfidence.Type type = 1;
|
||||||
public static final int TYPE_FIELD_NUMBER = 1;
|
public static final int TYPE_FIELD_NUMBER = 1;
|
||||||
@ -2460,6 +2536,16 @@ public final class Protos {
|
|||||||
return broadcastBy_.get(index);
|
return broadcastBy_.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optional .wallet.TransactionConfidence.Source source = 7;
|
||||||
|
public static final int SOURCE_FIELD_NUMBER = 7;
|
||||||
|
private org.bitcoinj.wallet.Protos.TransactionConfidence.Source source_;
|
||||||
|
public boolean hasSource() {
|
||||||
|
return ((bitField0_ & 0x00000020) == 0x00000020);
|
||||||
|
}
|
||||||
|
public org.bitcoinj.wallet.Protos.TransactionConfidence.Source getSource() {
|
||||||
|
return source_;
|
||||||
|
}
|
||||||
|
|
||||||
private void initFields() {
|
private void initFields() {
|
||||||
type_ = org.bitcoinj.wallet.Protos.TransactionConfidence.Type.UNKNOWN;
|
type_ = org.bitcoinj.wallet.Protos.TransactionConfidence.Type.UNKNOWN;
|
||||||
appearedAtHeight_ = 0;
|
appearedAtHeight_ = 0;
|
||||||
@ -2467,6 +2553,7 @@ public final class Protos {
|
|||||||
depth_ = 0;
|
depth_ = 0;
|
||||||
workDone_ = 0L;
|
workDone_ = 0L;
|
||||||
broadcastBy_ = java.util.Collections.emptyList();
|
broadcastBy_ = java.util.Collections.emptyList();
|
||||||
|
source_ = org.bitcoinj.wallet.Protos.TransactionConfidence.Source.SOURCE_UNKNOWN;
|
||||||
}
|
}
|
||||||
private byte memoizedIsInitialized = -1;
|
private byte memoizedIsInitialized = -1;
|
||||||
public final boolean isInitialized() {
|
public final boolean isInitialized() {
|
||||||
@ -2504,6 +2591,9 @@ public final class Protos {
|
|||||||
for (int i = 0; i < broadcastBy_.size(); i++) {
|
for (int i = 0; i < broadcastBy_.size(); i++) {
|
||||||
output.writeMessage(6, broadcastBy_.get(i));
|
output.writeMessage(6, broadcastBy_.get(i));
|
||||||
}
|
}
|
||||||
|
if (((bitField0_ & 0x00000020) == 0x00000020)) {
|
||||||
|
output.writeEnum(7, source_.getNumber());
|
||||||
|
}
|
||||||
getUnknownFields().writeTo(output);
|
getUnknownFields().writeTo(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2537,6 +2627,10 @@ public final class Protos {
|
|||||||
size += com.google.protobuf.CodedOutputStream
|
size += com.google.protobuf.CodedOutputStream
|
||||||
.computeMessageSize(6, broadcastBy_.get(i));
|
.computeMessageSize(6, broadcastBy_.get(i));
|
||||||
}
|
}
|
||||||
|
if (((bitField0_ & 0x00000020) == 0x00000020)) {
|
||||||
|
size += com.google.protobuf.CodedOutputStream
|
||||||
|
.computeEnumSize(7, source_.getNumber());
|
||||||
|
}
|
||||||
size += getUnknownFields().getSerializedSize();
|
size += getUnknownFields().getSerializedSize();
|
||||||
memoizedSerializedSize = size;
|
memoizedSerializedSize = size;
|
||||||
return size;
|
return size;
|
||||||
@ -2678,6 +2772,8 @@ public final class Protos {
|
|||||||
} else {
|
} else {
|
||||||
broadcastByBuilder_.clear();
|
broadcastByBuilder_.clear();
|
||||||
}
|
}
|
||||||
|
source_ = org.bitcoinj.wallet.Protos.TransactionConfidence.Source.SOURCE_UNKNOWN;
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000040);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2745,6 +2841,10 @@ public final class Protos {
|
|||||||
} else {
|
} else {
|
||||||
result.broadcastBy_ = broadcastByBuilder_.build();
|
result.broadcastBy_ = broadcastByBuilder_.build();
|
||||||
}
|
}
|
||||||
|
if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
|
||||||
|
to_bitField0_ |= 0x00000020;
|
||||||
|
}
|
||||||
|
result.source_ = source_;
|
||||||
result.bitField0_ = to_bitField0_;
|
result.bitField0_ = to_bitField0_;
|
||||||
onBuilt();
|
onBuilt();
|
||||||
return result;
|
return result;
|
||||||
@ -2802,6 +2902,9 @@ public final class Protos {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (other.hasSource()) {
|
||||||
|
setSource(other.getSource());
|
||||||
|
}
|
||||||
this.mergeUnknownFields(other.getUnknownFields());
|
this.mergeUnknownFields(other.getUnknownFields());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -2876,6 +2979,17 @@ public final class Protos {
|
|||||||
addBroadcastBy(subBuilder.buildPartial());
|
addBroadcastBy(subBuilder.buildPartial());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 56: {
|
||||||
|
int rawValue = input.readEnum();
|
||||||
|
org.bitcoinj.wallet.Protos.TransactionConfidence.Source value = org.bitcoinj.wallet.Protos.TransactionConfidence.Source.valueOf(rawValue);
|
||||||
|
if (value == null) {
|
||||||
|
unknownFields.mergeVarintField(7, rawValue);
|
||||||
|
} else {
|
||||||
|
bitField0_ |= 0x00000040;
|
||||||
|
source_ = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3179,6 +3293,30 @@ public final class Protos {
|
|||||||
return broadcastByBuilder_;
|
return broadcastByBuilder_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optional .wallet.TransactionConfidence.Source source = 7;
|
||||||
|
private org.bitcoinj.wallet.Protos.TransactionConfidence.Source source_ = org.bitcoinj.wallet.Protos.TransactionConfidence.Source.SOURCE_UNKNOWN;
|
||||||
|
public boolean hasSource() {
|
||||||
|
return ((bitField0_ & 0x00000040) == 0x00000040);
|
||||||
|
}
|
||||||
|
public org.bitcoinj.wallet.Protos.TransactionConfidence.Source getSource() {
|
||||||
|
return source_;
|
||||||
|
}
|
||||||
|
public Builder setSource(org.bitcoinj.wallet.Protos.TransactionConfidence.Source value) {
|
||||||
|
if (value == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
bitField0_ |= 0x00000040;
|
||||||
|
source_ = value;
|
||||||
|
onChanged();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public Builder clearSource() {
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000040);
|
||||||
|
source_ = org.bitcoinj.wallet.Protos.TransactionConfidence.Source.SOURCE_UNKNOWN;
|
||||||
|
onChanged();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// @@protoc_insertion_point(builder_scope:wallet.TransactionConfidence)
|
// @@protoc_insertion_point(builder_scope:wallet.TransactionConfidence)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6570,31 +6708,34 @@ public final class Protos {
|
|||||||
"ence\030\004 \001(\r\"\177\n\021TransactionOutput\022\r\n\005value",
|
"ence\030\004 \001(\r\"\177\n\021TransactionOutput\022\r\n\005value",
|
||||||
"\030\001 \002(\003\022\024\n\014script_bytes\030\002 \002(\014\022!\n\031spent_by" +
|
"\030\001 \002(\003\022\024\n\014script_bytes\030\002 \002(\014\022!\n\031spent_by" +
|
||||||
"_transaction_hash\030\003 \001(\014\022\"\n\032spent_by_tran" +
|
"_transaction_hash\030\003 \001(\014\022\"\n\032spent_by_tran" +
|
||||||
"saction_index\030\004 \001(\005\"\255\002\n\025TransactionConfi" +
|
"saction_index\030\004 \001(\005\"\246\003\n\025TransactionConfi" +
|
||||||
"dence\0220\n\004type\030\001 \001(\0162\".wallet.Transaction" +
|
"dence\0220\n\004type\030\001 \001(\0162\".wallet.Transaction" +
|
||||||
"Confidence.Type\022\032\n\022appeared_at_height\030\002 " +
|
"Confidence.Type\022\032\n\022appeared_at_height\030\002 " +
|
||||||
"\001(\005\022\036\n\026overriding_transaction\030\003 \001(\014\022\r\n\005d" +
|
"\001(\005\022\036\n\026overriding_transaction\030\003 \001(\014\022\r\n\005d" +
|
||||||
"epth\030\004 \001(\005\022\021\n\twork_done\030\005 \001(\003\022)\n\014broadca" +
|
"epth\030\004 \001(\005\022\021\n\twork_done\030\005 \001(\003\022)\n\014broadca" +
|
||||||
"st_by\030\006 \003(\0132\023.wallet.PeerAddress\"Y\n\004Type" +
|
"st_by\030\006 \003(\0132\023.wallet.PeerAddress\0224\n\006sour" +
|
||||||
"\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDING\020\001\022\025\n\021NOT_SEEN_" +
|
"ce\030\007 \001(\0162$.wallet.TransactionConfidence." +
|
||||||
"IN_CHAIN\020\002\022\025\n\021NOT_IN_BEST_CHAIN\020\003\022\010\n\004DEA",
|
"Source\"Y\n\004Type\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDING\020",
|
||||||
"D\020\004\"\211\003\n\013Transaction\022\017\n\007version\030\001 \002(\005\022\014\n\004" +
|
"\001\022\025\n\021NOT_SEEN_IN_CHAIN\020\002\022\025\n\021NOT_IN_BEST_" +
|
||||||
"hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162\030.wallet.Transa" +
|
"CHAIN\020\003\022\010\n\004DEAD\020\004\"A\n\006Source\022\022\n\016SOURCE_UN" +
|
||||||
"ction.Pool\022\021\n\tlock_time\030\004 \001(\r\022\022\n\nupdated" +
|
"KNOWN\020\000\022\022\n\016SOURCE_NETWORK\020\001\022\017\n\013SOURCE_SE" +
|
||||||
"_at\030\005 \001(\003\0223\n\021transaction_input\030\006 \003(\0132\030.w" +
|
"LF\020\002\"\211\003\n\013Transaction\022\017\n\007version\030\001 \002(\005\022\014\n" +
|
||||||
"allet.TransactionInput\0225\n\022transaction_ou" +
|
"\004hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162\030.wallet.Trans" +
|
||||||
"tput\030\007 \003(\0132\031.wallet.TransactionOutput\022\022\n" +
|
"action.Pool\022\021\n\tlock_time\030\004 \001(\r\022\022\n\nupdate" +
|
||||||
"\nblock_hash\030\010 \003(\014\0221\n\nconfidence\030\t \001(\0132\035." +
|
"d_at\030\005 \001(\003\0223\n\021transaction_input\030\006 \003(\0132\030." +
|
||||||
"wallet.TransactionConfidence\"Y\n\004Pool\022\013\n\007" +
|
"wallet.TransactionInput\0225\n\022transaction_o" +
|
||||||
"UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n\004DE" +
|
"utput\030\007 \003(\0132\031.wallet.TransactionOutput\022\022" +
|
||||||
"AD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE\020\022\"",
|
"\n\nblock_hash\030\010 \003(\014\0221\n\nconfidence\030\t \001(\0132\035",
|
||||||
"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\022\021" +
|
".wallet.TransactionConfidence\"Y\n\004Pool\022\013\n" +
|
||||||
"\n\tmandatory\030\003 \002(\010\"\254\001\n\006Wallet\022\032\n\022network_" +
|
"\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n\004D" +
|
||||||
"identifier\030\001 \002(\t\022\034\n\024last_seen_block_hash" +
|
"EAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE\020\022" +
|
||||||
"\030\002 \001(\014\022\030\n\003key\030\003 \003(\0132\013.wallet.Key\022(\n\013tran" +
|
"\"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\022" +
|
||||||
"saction\030\004 \003(\0132\023.wallet.Transaction\022$\n\tex" +
|
"\021\n\tmandatory\030\003 \002(\010\"\254\001\n\006Wallet\022\032\n\022network" +
|
||||||
"tension\030\n \003(\0132\021.wallet.ExtensionB\035\n\023org." +
|
"_identifier\030\001 \002(\t\022\034\n\024last_seen_block_has" +
|
||||||
"bitcoinj.walletB\006Protos"
|
"h\030\002 \001(\014\022\030\n\003key\030\003 \003(\0132\013.wallet.Key\022(\n\013tra" +
|
||||||
|
"nsaction\030\004 \003(\0132\023.wallet.Transaction\022$\n\te" +
|
||||||
|
"xtension\030\n \003(\0132\021.wallet.ExtensionB\035\n\023org" +
|
||||||
|
".bitcoinj.walletB\006Protos"
|
||||||
};
|
};
|
||||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||||
@ -6638,7 +6779,7 @@ public final class Protos {
|
|||||||
internal_static_wallet_TransactionConfidence_fieldAccessorTable = new
|
internal_static_wallet_TransactionConfidence_fieldAccessorTable = new
|
||||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||||
internal_static_wallet_TransactionConfidence_descriptor,
|
internal_static_wallet_TransactionConfidence_descriptor,
|
||||||
new java.lang.String[] { "Type", "AppearedAtHeight", "OverridingTransaction", "Depth", "WorkDone", "BroadcastBy", },
|
new java.lang.String[] { "Type", "AppearedAtHeight", "OverridingTransaction", "Depth", "WorkDone", "BroadcastBy", "Source", },
|
||||||
org.bitcoinj.wallet.Protos.TransactionConfidence.class,
|
org.bitcoinj.wallet.Protos.TransactionConfidence.class,
|
||||||
org.bitcoinj.wallet.Protos.TransactionConfidence.Builder.class);
|
org.bitcoinj.wallet.Protos.TransactionConfidence.Builder.class);
|
||||||
internal_static_wallet_Transaction_descriptor =
|
internal_static_wallet_Transaction_descriptor =
|
||||||
|
@ -153,8 +153,10 @@ public class TestUtils {
|
|||||||
Address to = new ECKey().toAddress(chainHead.params);
|
Address to = new ECKey().toAddress(chainHead.params);
|
||||||
Block b = chainHead.createNextBlock(to, timeSeconds);
|
Block b = chainHead.createNextBlock(to, timeSeconds);
|
||||||
// Coinbase tx was already added.
|
// Coinbase tx was already added.
|
||||||
for (Transaction tx : transactions)
|
for (Transaction tx : transactions) {
|
||||||
|
tx.getConfidence().setSource(TransactionConfidence.Source.NETWORK);
|
||||||
b.addTransaction(tx);
|
b.addTransaction(tx);
|
||||||
|
}
|
||||||
b.solve();
|
b.solve();
|
||||||
BlockPair pair = new BlockPair();
|
BlockPair pair = new BlockPair();
|
||||||
pair.block = b;
|
pair.block = b;
|
||||||
|
@ -94,6 +94,7 @@ public class WalletTest {
|
|||||||
Transaction t2 = req.tx;
|
Transaction t2 = req.tx;
|
||||||
assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
|
assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
|
||||||
assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.ALL));
|
assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.ALL));
|
||||||
|
assertEquals(TransactionConfidence.Source.SELF, t2.getConfidence().getSource());
|
||||||
|
|
||||||
// Do some basic sanity checks.
|
// Do some basic sanity checks.
|
||||||
assertEquals(1, t2.getInputs().size());
|
assertEquals(1, t2.getInputs().size());
|
||||||
|
@ -56,13 +56,15 @@ public class WalletProtobufSerializerTest {
|
|||||||
Transaction t1 = createFakeTx(params, v1, myAddress);
|
Transaction t1 = createFakeTx(params, v1, myAddress);
|
||||||
t1.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("1.2.3.4")));
|
t1.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("1.2.3.4")));
|
||||||
t1.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("5.6.7.8")));
|
t1.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("5.6.7.8")));
|
||||||
myWallet.receiveFromBlock(t1, null, BlockChain.NewBlockType.BEST_CHAIN);
|
t1.getConfidence().setSource(TransactionConfidence.Source.NETWORK);
|
||||||
|
myWallet.receivePending(t1, new ArrayList<Transaction>());
|
||||||
Wallet wallet1 = roundTrip(myWallet);
|
Wallet wallet1 = roundTrip(myWallet);
|
||||||
assertEquals(1, wallet1.getTransactions(true, true).size());
|
assertEquals(1, wallet1.getTransactions(true, true).size());
|
||||||
assertEquals(v1, wallet1.getBalance());
|
assertEquals(v1, wallet1.getBalance(Wallet.BalanceType.ESTIMATED));
|
||||||
assertArrayEquals(t1.bitcoinSerialize(),
|
Transaction t1copy = wallet1.getTransaction(t1.getHash());
|
||||||
wallet1.getTransaction(t1.getHash()).bitcoinSerialize());
|
assertArrayEquals(t1.bitcoinSerialize(), t1copy.bitcoinSerialize());
|
||||||
assertEquals(2, wallet1.getTransaction(t1.getHash()).getConfidence().numBroadcastPeers());
|
assertEquals(2, t1copy.getConfidence().numBroadcastPeers());
|
||||||
|
assertEquals(TransactionConfidence.Source.NETWORK, t1copy.getConfidence().getSource());
|
||||||
|
|
||||||
Protos.Wallet walletProto = new WalletProtobufSerializer().walletToProto(myWallet);
|
Protos.Wallet walletProto = new WalletProtobufSerializer().walletToProto(myWallet);
|
||||||
assertEquals(Protos.Key.Type.ORIGINAL, walletProto.getKey(0).getType());
|
assertEquals(Protos.Key.Type.ORIGINAL, walletProto.getKey(0).getType());
|
||||||
@ -73,7 +75,7 @@ public class WalletProtobufSerializerTest {
|
|||||||
Protos.Transaction t1p = walletProto.getTransaction(0);
|
Protos.Transaction t1p = walletProto.getTransaction(0);
|
||||||
assertEquals(0, t1p.getBlockHashCount());
|
assertEquals(0, t1p.getBlockHashCount());
|
||||||
assertArrayEquals(t1.getHash().getBytes(), t1p.getHash().toByteArray());
|
assertArrayEquals(t1.getHash().getBytes(), t1p.getHash().toByteArray());
|
||||||
assertEquals(Protos.Transaction.Pool.UNSPENT, t1p.getPool());
|
assertEquals(Protos.Transaction.Pool.PENDING, t1p.getPool());
|
||||||
assertFalse(t1p.hasLockTime());
|
assertFalse(t1p.hasLockTime());
|
||||||
assertFalse(t1p.getTransactionInput(0).hasSequence());
|
assertFalse(t1p.getTransactionInput(0).hasSequence());
|
||||||
assertArrayEquals(t1.getInputs().get(0).getOutpoint().getHash().getBytes(),
|
assertArrayEquals(t1.getInputs().get(0).getOutpoint().getHash().getBytes(),
|
||||||
|
Loading…
Reference in New Issue
Block a user