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:
|
||||
* - 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;
|
||||
@ -115,6 +116,18 @@ message TransactionConfidence {
|
||||
optional int64 work_done = 5;
|
||||
|
||||
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 */
|
||||
|
@ -185,6 +185,8 @@ public class Block extends Message {
|
||||
transactions = new ArrayList<Transaction>(numTransactions);
|
||||
for (int i = 0; i < numTransactions; i++) {
|
||||
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);
|
||||
cursor += tx.getMessageSize();
|
||||
optimalEncodingMessageSize += tx.getOptimalEncodingMessageSize();
|
||||
|
@ -416,6 +416,9 @@ public class Peer {
|
||||
tx = memoryPool.seen(tx, getAddress());
|
||||
}
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
|
@ -67,43 +67,11 @@ public class TransactionConfidence implements Serializable {
|
||||
// Lazily created listeners array.
|
||||
private transient ArrayList<Listener> listeners;
|
||||
|
||||
/**
|
||||
* The depth of the transaction on the best chain in blocks. An unconfirmed block has depth 0, after one confirmation
|
||||
* its depth is 1.
|
||||
*/
|
||||
// The depth of the transaction on the best chain in blocks. An unconfirmed block has depth 0.
|
||||
private int depth;
|
||||
|
||||
/**
|
||||
* The cumulative work done for the blocks that bury this transaction. BigInteger.ZERO if the transaction is not
|
||||
* on the best chain.
|
||||
*/
|
||||
// The cumulative work done for the blocks that bury this transaction.
|
||||
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. */
|
||||
public enum ConfidenceType {
|
||||
/** 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
|
||||
* 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);
|
||||
};
|
||||
|
||||
private ConfidenceType confidenceType = ConfidenceType.UNKNOWN;
|
||||
private int appearedAtChainHeight = -1;
|
||||
private Transaction overridingTransaction;
|
||||
/**
|
||||
* <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 TransactionConfidence(Transaction tx) {
|
||||
// Assume a default number of peers for our set.
|
||||
broadcastBy = new CopyOnWriteArrayList<PeerAddress>();
|
||||
transaction = tx;
|
||||
public synchronized void removeEventListener(Listener listener) {
|
||||
Preconditions.checkNotNull(listener);
|
||||
Preconditions.checkNotNull(listeners);
|
||||
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),
|
||||
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
|
||||
// the Peer before we got to this point, but in some cases (unit tests, other sources of transactions) it may
|
||||
// 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.
|
||||
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;
|
||||
log.info(" completed {}", req.tx.getHashAsString());
|
||||
return true;
|
||||
|
@ -213,6 +213,15 @@ public class WalletProtobufSerializer {
|
||||
Sha256Hash overridingHash = confidence.getOverridingTransaction().getHash();
|
||||
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();) {
|
||||
PeerAddress address = it.next();
|
||||
@ -423,5 +432,12 @@ public class WalletProtobufSerializer {
|
||||
address.setServices(BigInteger.valueOf(proto.getServices()));
|
||||
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();
|
||||
org.bitcoinj.wallet.Protos.PeerAddressOrBuilder getBroadcastByOrBuilder(
|
||||
int index);
|
||||
|
||||
// optional .wallet.TransactionConfidence.Source source = 7;
|
||||
boolean hasSource();
|
||||
org.bitcoinj.wallet.Protos.TransactionConfidence.Source getSource();
|
||||
}
|
||||
public static final class TransactionConfidence extends
|
||||
com.google.protobuf.GeneratedMessage
|
||||
@ -2388,6 +2392,78 @@ public final class Protos {
|
||||
// @@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_;
|
||||
// optional .wallet.TransactionConfidence.Type type = 1;
|
||||
public static final int TYPE_FIELD_NUMBER = 1;
|
||||
@ -2460,6 +2536,16 @@ public final class Protos {
|
||||
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() {
|
||||
type_ = org.bitcoinj.wallet.Protos.TransactionConfidence.Type.UNKNOWN;
|
||||
appearedAtHeight_ = 0;
|
||||
@ -2467,6 +2553,7 @@ public final class Protos {
|
||||
depth_ = 0;
|
||||
workDone_ = 0L;
|
||||
broadcastBy_ = java.util.Collections.emptyList();
|
||||
source_ = org.bitcoinj.wallet.Protos.TransactionConfidence.Source.SOURCE_UNKNOWN;
|
||||
}
|
||||
private byte memoizedIsInitialized = -1;
|
||||
public final boolean isInitialized() {
|
||||
@ -2504,6 +2591,9 @@ public final class Protos {
|
||||
for (int i = 0; i < broadcastBy_.size(); i++) {
|
||||
output.writeMessage(6, broadcastBy_.get(i));
|
||||
}
|
||||
if (((bitField0_ & 0x00000020) == 0x00000020)) {
|
||||
output.writeEnum(7, source_.getNumber());
|
||||
}
|
||||
getUnknownFields().writeTo(output);
|
||||
}
|
||||
|
||||
@ -2537,6 +2627,10 @@ public final class Protos {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeMessageSize(6, broadcastBy_.get(i));
|
||||
}
|
||||
if (((bitField0_ & 0x00000020) == 0x00000020)) {
|
||||
size += com.google.protobuf.CodedOutputStream
|
||||
.computeEnumSize(7, source_.getNumber());
|
||||
}
|
||||
size += getUnknownFields().getSerializedSize();
|
||||
memoizedSerializedSize = size;
|
||||
return size;
|
||||
@ -2678,6 +2772,8 @@ public final class Protos {
|
||||
} else {
|
||||
broadcastByBuilder_.clear();
|
||||
}
|
||||
source_ = org.bitcoinj.wallet.Protos.TransactionConfidence.Source.SOURCE_UNKNOWN;
|
||||
bitField0_ = (bitField0_ & ~0x00000040);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -2745,6 +2841,10 @@ public final class Protos {
|
||||
} else {
|
||||
result.broadcastBy_ = broadcastByBuilder_.build();
|
||||
}
|
||||
if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
|
||||
to_bitField0_ |= 0x00000020;
|
||||
}
|
||||
result.source_ = source_;
|
||||
result.bitField0_ = to_bitField0_;
|
||||
onBuilt();
|
||||
return result;
|
||||
@ -2802,6 +2902,9 @@ public final class Protos {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (other.hasSource()) {
|
||||
setSource(other.getSource());
|
||||
}
|
||||
this.mergeUnknownFields(other.getUnknownFields());
|
||||
return this;
|
||||
}
|
||||
@ -2876,6 +2979,17 @@ public final class Protos {
|
||||
addBroadcastBy(subBuilder.buildPartial());
|
||||
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_;
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
@ -6570,31 +6708,34 @@ public final class Protos {
|
||||
"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" +
|
||||
"_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" +
|
||||
"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" +
|
||||
"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" +
|
||||
"\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDING\020\001\022\025\n\021NOT_SEEN_" +
|
||||
"IN_CHAIN\020\002\022\025\n\021NOT_IN_BEST_CHAIN\020\003\022\010\n\004DEA",
|
||||
"D\020\004\"\211\003\n\013Transaction\022\017\n\007version\030\001 \002(\005\022\014\n\004" +
|
||||
"hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162\030.wallet.Transa" +
|
||||
"ction.Pool\022\021\n\tlock_time\030\004 \001(\r\022\022\n\nupdated" +
|
||||
"_at\030\005 \001(\003\0223\n\021transaction_input\030\006 \003(\0132\030.w" +
|
||||
"allet.TransactionInput\0225\n\022transaction_ou" +
|
||||
"tput\030\007 \003(\0132\031.wallet.TransactionOutput\022\022\n" +
|
||||
"\nblock_hash\030\010 \003(\014\0221\n\nconfidence\030\t \001(\0132\035." +
|
||||
"wallet.TransactionConfidence\"Y\n\004Pool\022\013\n\007" +
|
||||
"UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n\004DE" +
|
||||
"AD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE\020\022\"",
|
||||
"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\022\021" +
|
||||
"\n\tmandatory\030\003 \002(\010\"\254\001\n\006Wallet\022\032\n\022network_" +
|
||||
"identifier\030\001 \002(\t\022\034\n\024last_seen_block_hash" +
|
||||
"\030\002 \001(\014\022\030\n\003key\030\003 \003(\0132\013.wallet.Key\022(\n\013tran" +
|
||||
"saction\030\004 \003(\0132\023.wallet.Transaction\022$\n\tex" +
|
||||
"tension\030\n \003(\0132\021.wallet.ExtensionB\035\n\023org." +
|
||||
"bitcoinj.walletB\006Protos"
|
||||
"st_by\030\006 \003(\0132\023.wallet.PeerAddress\0224\n\006sour" +
|
||||
"ce\030\007 \001(\0162$.wallet.TransactionConfidence." +
|
||||
"Source\"Y\n\004Type\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDING\020",
|
||||
"\001\022\025\n\021NOT_SEEN_IN_CHAIN\020\002\022\025\n\021NOT_IN_BEST_" +
|
||||
"CHAIN\020\003\022\010\n\004DEAD\020\004\"A\n\006Source\022\022\n\016SOURCE_UN" +
|
||||
"KNOWN\020\000\022\022\n\016SOURCE_NETWORK\020\001\022\017\n\013SOURCE_SE" +
|
||||
"LF\020\002\"\211\003\n\013Transaction\022\017\n\007version\030\001 \002(\005\022\014\n" +
|
||||
"\004hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162\030.wallet.Trans" +
|
||||
"action.Pool\022\021\n\tlock_time\030\004 \001(\r\022\022\n\nupdate" +
|
||||
"d_at\030\005 \001(\003\0223\n\021transaction_input\030\006 \003(\0132\030." +
|
||||
"wallet.TransactionInput\0225\n\022transaction_o" +
|
||||
"utput\030\007 \003(\0132\031.wallet.TransactionOutput\022\022" +
|
||||
"\n\nblock_hash\030\010 \003(\014\0221\n\nconfidence\030\t \001(\0132\035",
|
||||
".wallet.TransactionConfidence\"Y\n\004Pool\022\013\n" +
|
||||
"\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n\004D" +
|
||||
"EAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE\020\022" +
|
||||
"\"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\022" +
|
||||
"\021\n\tmandatory\030\003 \002(\010\"\254\001\n\006Wallet\022\032\n\022network" +
|
||||
"_identifier\030\001 \002(\t\022\034\n\024last_seen_block_has" +
|
||||
"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 =
|
||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||
@ -6638,7 +6779,7 @@ public final class Protos {
|
||||
internal_static_wallet_TransactionConfidence_fieldAccessorTable = new
|
||||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
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.Builder.class);
|
||||
internal_static_wallet_Transaction_descriptor =
|
||||
|
@ -153,8 +153,10 @@ public class TestUtils {
|
||||
Address to = new ECKey().toAddress(chainHead.params);
|
||||
Block b = chainHead.createNextBlock(to, timeSeconds);
|
||||
// Coinbase tx was already added.
|
||||
for (Transaction tx : transactions)
|
||||
for (Transaction tx : transactions) {
|
||||
tx.getConfidence().setSource(TransactionConfidence.Source.NETWORK);
|
||||
b.addTransaction(tx);
|
||||
}
|
||||
b.solve();
|
||||
BlockPair pair = new BlockPair();
|
||||
pair.block = b;
|
||||
|
@ -94,6 +94,7 @@ public class WalletTest {
|
||||
Transaction t2 = req.tx;
|
||||
assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT));
|
||||
assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.ALL));
|
||||
assertEquals(TransactionConfidence.Source.SELF, t2.getConfidence().getSource());
|
||||
|
||||
// Do some basic sanity checks.
|
||||
assertEquals(1, t2.getInputs().size());
|
||||
|
@ -56,13 +56,15 @@ public class WalletProtobufSerializerTest {
|
||||
Transaction t1 = createFakeTx(params, v1, myAddress);
|
||||
t1.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("1.2.3.4")));
|
||||
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);
|
||||
assertEquals(1, wallet1.getTransactions(true, true).size());
|
||||
assertEquals(v1, wallet1.getBalance());
|
||||
assertArrayEquals(t1.bitcoinSerialize(),
|
||||
wallet1.getTransaction(t1.getHash()).bitcoinSerialize());
|
||||
assertEquals(2, wallet1.getTransaction(t1.getHash()).getConfidence().numBroadcastPeers());
|
||||
assertEquals(v1, wallet1.getBalance(Wallet.BalanceType.ESTIMATED));
|
||||
Transaction t1copy = wallet1.getTransaction(t1.getHash());
|
||||
assertArrayEquals(t1.bitcoinSerialize(), t1copy.bitcoinSerialize());
|
||||
assertEquals(2, t1copy.getConfidence().numBroadcastPeers());
|
||||
assertEquals(TransactionConfidence.Source.NETWORK, t1copy.getConfidence().getSource());
|
||||
|
||||
Protos.Wallet walletProto = new WalletProtobufSerializer().walletToProto(myWallet);
|
||||
assertEquals(Protos.Key.Type.ORIGINAL, walletProto.getKey(0).getType());
|
||||
@ -73,7 +75,7 @@ public class WalletProtobufSerializerTest {
|
||||
Protos.Transaction t1p = walletProto.getTransaction(0);
|
||||
assertEquals(0, t1p.getBlockHashCount());
|
||||
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.getTransactionInput(0).hasSequence());
|
||||
assertArrayEquals(t1.getInputs().get(0).getOutpoint().getHash().getBytes(),
|
||||
|
Loading…
Reference in New Issue
Block a user