Support for recording a memo with transactions. It can be used to record the memo of the payment request that initiated the transaction. Use the new SendRequest.memo register.

This commit is contained in:
Andreas Schildbach 2014-09-03 14:28:36 +02:00
parent d09b69ebc5
commit 7d930554a6
7 changed files with 309 additions and 35 deletions

View File

@ -161,6 +161,12 @@ public class Transaction extends ChildMessage implements Serializable {
@Nullable @Nullable
private ExchangeRate exchangeRate; private ExchangeRate exchangeRate;
/**
* This field can be used to record the memo of the payment request that initiated the transaction. It's optional.
*/
@Nullable
private String memo;
public Transaction(NetworkParameters params) { public Transaction(NetworkParameters params) {
super(params); super(params);
version = 1; version = 1;
@ -1304,4 +1310,19 @@ public class Transaction extends ChildMessage implements Serializable {
public void setExchangeRate(ExchangeRate exchangeRate) { public void setExchangeRate(ExchangeRate exchangeRate) {
this.exchangeRate = exchangeRate; this.exchangeRate = exchangeRate;
} }
/**
* Returns the transaction {@link #memo}.
*/
public String getMemo() {
return memo;
}
/**
* Set the transaction {@link #memo}. It can be used to record the memo of the payment request that initiated the
* transaction.
*/
public void setMemo(String memo) {
this.memo = memo;
}
} }

View File

@ -44,6 +44,8 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import org.bitcoin.protocols.payments.Protos.PaymentDetails;
import org.bitcoinj.wallet.Protos; import org.bitcoinj.wallet.Protos;
import org.bitcoinj.wallet.Protos.Wallet.EncryptionType; import org.bitcoinj.wallet.Protos.Wallet.EncryptionType;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -3032,6 +3034,12 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
*/ */
public ExchangeRate exchangeRate = null; public ExchangeRate exchangeRate = null;
/**
* If not null, this memo is recorded with the transaction during completion. It can be used to record the memo
* of the payment request that initiated the transaction.
*/
public String memo = null;
// Tracks if this has been passed to wallet.completeTx already: just a safety check. // Tracks if this has been passed to wallet.completeTx already: just a safety check.
private boolean completed; private boolean completed;
@ -3084,6 +3092,13 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
return req; return req;
} }
/** Copy data from payment request. */
public SendRequest fromPaymentDetails(PaymentDetails paymentDetails) {
if (paymentDetails.hasMemo())
this.memo = paymentDetails.getMemo();
return this;
}
@Override @Override
public String toString() { public String toString() {
// print only the user-settable fields // print only the user-settable fields
@ -3399,6 +3414,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
req.tx.setPurpose(Transaction.Purpose.USER_PAYMENT); req.tx.setPurpose(Transaction.Purpose.USER_PAYMENT);
// Record the exchange rate that was valid when the transaction was completed. // Record the exchange rate that was valid when the transaction was completed.
req.tx.setExchangeRate(req.exchangeRate); req.tx.setExchangeRate(req.exchangeRate);
req.tx.setMemo(req.memo);
req.completed = true; req.completed = true;
req.fee = calculatedFee; req.fee = calculatedFee;
log.info(" completed: {}", req.tx); log.info(" completed: {}", req.tx);

View File

@ -15,6 +15,7 @@
package com.google.bitcoin.protocols.payments; package com.google.bitcoin.protocols.payments;
import com.google.bitcoin.core.*; import com.google.bitcoin.core.*;
import com.google.bitcoin.core.Wallet.SendRequest;
import com.google.bitcoin.crypto.TrustStoreLoader; import com.google.bitcoin.crypto.TrustStoreLoader;
import com.google.bitcoin.params.MainNetParams; import com.google.bitcoin.params.MainNetParams;
import com.google.bitcoin.protocols.payments.PaymentProtocol.PkiVerificationData; import com.google.bitcoin.protocols.payments.PaymentProtocol.PkiVerificationData;
@ -297,7 +298,7 @@ public class PaymentSession {
Transaction tx = new Transaction(params); Transaction tx = new Transaction(params);
for (Protos.Output output : paymentDetails.getOutputsList()) for (Protos.Output output : paymentDetails.getOutputsList())
tx.addOutput(new TransactionOutput(params, tx, Coin.valueOf(output.getAmount()), output.getScript().toByteArray())); tx.addOutput(new TransactionOutput(params, tx, Coin.valueOf(output.getAmount()), output.getScript().toByteArray()));
return Wallet.SendRequest.forTx(tx); return Wallet.SendRequest.forTx(tx).fromPaymentDetails(paymentDetails);
} }
/** /**

View File

@ -300,6 +300,9 @@ public class WalletProtobufSerializer {
.setFiatCurrencyCode(exchangeRate.fiat.currencyCode); .setFiatCurrencyCode(exchangeRate.fiat.currencyCode);
txBuilder.setExchangeRate(exchangeRateBuilder); txBuilder.setExchangeRate(exchangeRateBuilder);
} }
if (tx.getMemo() != null)
txBuilder.setMemo(tx.getMemo());
return txBuilder.build(); return txBuilder.build();
} }
@ -592,6 +595,9 @@ public class WalletProtobufSerializer {
exchangeRateProto.getFiatCurrencyCode(), exchangeRateProto.getFiatValue()))); exchangeRateProto.getFiatCurrencyCode(), exchangeRateProto.getFiatValue())));
} }
if (txProto.hasMemo())
tx.setMemo(txProto.getMemo());
// Transaction should now be complete. // Transaction should now be complete.
Sha256Hash protoHash = byteStringToHash(txProto.getHash()); Sha256Hash protoHash = byteStringToHash(txProto.getHash());
if (!tx.getHash().equals(protoHash)) if (!tx.getHash().equals(protoHash))

View File

@ -7819,6 +7819,36 @@ public final class Protos {
* </pre> * </pre>
*/ */
org.bitcoinj.wallet.Protos.ExchangeRateOrBuilder getExchangeRateOrBuilder(); org.bitcoinj.wallet.Protos.ExchangeRateOrBuilder getExchangeRateOrBuilder();
// optional string memo = 13;
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
boolean hasMemo();
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
java.lang.String getMemo();
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
com.google.protobuf.ByteString
getMemoBytes();
} }
/** /**
* Protobuf type {@code wallet.Transaction} * Protobuf type {@code wallet.Transaction}
@ -7984,6 +8014,11 @@ public final class Protos {
bitField0_ |= 0x00000080; bitField0_ |= 0x00000080;
break; break;
} }
case 106: {
bitField0_ |= 0x00000100;
memo_ = input.readBytes();
break;
}
} }
} }
} catch (com.google.protobuf.InvalidProtocolBufferException e) { } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@ -8712,6 +8747,64 @@ public final class Protos {
return exchangeRate_; return exchangeRate_;
} }
// optional string memo = 13;
public static final int MEMO_FIELD_NUMBER = 13;
private java.lang.Object memo_;
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
public boolean hasMemo() {
return ((bitField0_ & 0x00000100) == 0x00000100);
}
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
public java.lang.String getMemo() {
java.lang.Object ref = memo_;
if (ref instanceof java.lang.String) {
return (java.lang.String) ref;
} else {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
java.lang.String s = bs.toStringUtf8();
if (bs.isValidUtf8()) {
memo_ = s;
}
return s;
}
}
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
public com.google.protobuf.ByteString
getMemoBytes() {
java.lang.Object ref = memo_;
if (ref instanceof java.lang.String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
memo_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
private void initFields() { private void initFields() {
version_ = 0; version_ = 0;
hash_ = com.google.protobuf.ByteString.EMPTY; hash_ = com.google.protobuf.ByteString.EMPTY;
@ -8725,6 +8818,7 @@ public final class Protos {
confidence_ = org.bitcoinj.wallet.Protos.TransactionConfidence.getDefaultInstance(); confidence_ = org.bitcoinj.wallet.Protos.TransactionConfidence.getDefaultInstance();
purpose_ = org.bitcoinj.wallet.Protos.Transaction.Purpose.UNKNOWN; purpose_ = org.bitcoinj.wallet.Protos.Transaction.Purpose.UNKNOWN;
exchangeRate_ = org.bitcoinj.wallet.Protos.ExchangeRate.getDefaultInstance(); exchangeRate_ = org.bitcoinj.wallet.Protos.ExchangeRate.getDefaultInstance();
memo_ = "";
} }
private byte memoizedIsInitialized = -1; private byte memoizedIsInitialized = -1;
public final boolean isInitialized() { public final boolean isInitialized() {
@ -8806,6 +8900,9 @@ public final class Protos {
if (((bitField0_ & 0x00000080) == 0x00000080)) { if (((bitField0_ & 0x00000080) == 0x00000080)) {
output.writeMessage(12, exchangeRate_); output.writeMessage(12, exchangeRate_);
} }
if (((bitField0_ & 0x00000100) == 0x00000100)) {
output.writeBytes(13, getMemoBytes());
}
getUnknownFields().writeTo(output); getUnknownFields().writeTo(output);
} }
@ -8873,6 +8970,10 @@ public final class Protos {
size += com.google.protobuf.CodedOutputStream size += com.google.protobuf.CodedOutputStream
.computeMessageSize(12, exchangeRate_); .computeMessageSize(12, exchangeRate_);
} }
if (((bitField0_ & 0x00000100) == 0x00000100)) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(13, getMemoBytes());
}
size += getUnknownFields().getSerializedSize(); size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size; memoizedSerializedSize = size;
return size; return size;
@ -9033,6 +9134,8 @@ public final class Protos {
exchangeRateBuilder_.clear(); exchangeRateBuilder_.clear();
} }
bitField0_ = (bitField0_ & ~0x00000800); bitField0_ = (bitField0_ & ~0x00000800);
memo_ = "";
bitField0_ = (bitField0_ & ~0x00001000);
return this; return this;
} }
@ -9129,6 +9232,10 @@ public final class Protos {
} else { } else {
result.exchangeRate_ = exchangeRateBuilder_.build(); result.exchangeRate_ = exchangeRateBuilder_.build();
} }
if (((from_bitField0_ & 0x00001000) == 0x00001000)) {
to_bitField0_ |= 0x00000100;
}
result.memo_ = memo_;
result.bitField0_ = to_bitField0_; result.bitField0_ = to_bitField0_;
onBuilt(); onBuilt();
return result; return result;
@ -9241,6 +9348,11 @@ public final class Protos {
if (other.hasExchangeRate()) { if (other.hasExchangeRate()) {
mergeExchangeRate(other.getExchangeRate()); mergeExchangeRate(other.getExchangeRate());
} }
if (other.hasMemo()) {
bitField0_ |= 0x00001000;
memo_ = other.memo_;
onChanged();
}
this.mergeUnknownFields(other.getUnknownFields()); this.mergeUnknownFields(other.getUnknownFields());
return this; return this;
} }
@ -10542,6 +10654,110 @@ public final class Protos {
return exchangeRateBuilder_; return exchangeRateBuilder_;
} }
// optional string memo = 13;
private java.lang.Object memo_ = "";
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
public boolean hasMemo() {
return ((bitField0_ & 0x00001000) == 0x00001000);
}
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
public java.lang.String getMemo() {
java.lang.Object ref = memo_;
if (!(ref instanceof java.lang.String)) {
java.lang.String s = ((com.google.protobuf.ByteString) ref)
.toStringUtf8();
memo_ = s;
return s;
} else {
return (java.lang.String) ref;
}
}
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
public com.google.protobuf.ByteString
getMemoBytes() {
java.lang.Object ref = memo_;
if (ref instanceof String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
memo_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
public Builder setMemo(
java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00001000;
memo_ = value;
onChanged();
return this;
}
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
public Builder clearMemo() {
bitField0_ = (bitField0_ & ~0x00001000);
memo_ = getDefaultInstance().getMemo();
onChanged();
return this;
}
/**
* <code>optional string memo = 13;</code>
*
* <pre>
* Memo of the transaction. It can be used to record the memo of the payment request that initiated the
* transaction.
* </pre>
*/
public Builder setMemoBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
bitField0_ |= 0x00001000;
memo_ = value;
onChanged();
return this;
}
// @@protoc_insertion_point(builder_scope:wallet.Transaction) // @@protoc_insertion_point(builder_scope:wallet.Transaction)
} }
@ -18299,7 +18515,7 @@ public final class Protos {
"Type\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDING\020\001\022\013\n\007PENDI" + "Type\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDING\020\001\022\013\n\007PENDI" +
"NG\020\002\022\025\n\021NOT_IN_BEST_CHAIN\020\003\022\010\n\004DEAD\020\004\"A\n" + "NG\020\002\022\025\n\021NOT_IN_BEST_CHAIN\020\003\022\010\n\004DEAD\020\004\"A\n" +
"\006Source\022\022\n\016SOURCE_UNKNOWN\020\000\022\022\n\016SOURCE_NE" + "\006Source\022\022\n\016SOURCE_UNKNOWN\020\000\022\022\n\016SOURCE_NE" +
"TWORK\020\001\022\017\n\013SOURCE_SELF\020\002\"\246\005\n\013Transaction" + "TWORK\020\001\022\017\n\013SOURCE_SELF\020\002\"\264\005\n\013Transaction" +
"\022\017\n\007version\030\001 \002(\005\022\014\n\004hash\030\002 \002(\014\022&\n\004pool\030" + "\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.Transaction.Pool\022\021\n\tlock_" + "\003 \001(\0162\030.wallet.Transaction.Pool\022\021\n\tlock_" +
"time\030\004 \001(\r\022\022\n\nupdated_at\030\005 \001(\003\0223\n\021transa" + "time\030\004 \001(\r\022\022\n\nupdated_at\030\005 \001(\003\0223\n\021transa" +
@ -18310,37 +18526,38 @@ public final class Protos {
"idence\030\t \001(\0132\035.wallet.TransactionConfide" + "idence\030\t \001(\0132\035.wallet.TransactionConfide" +
"nce\0225\n\007purpose\030\n \001(\0162\033.wallet.Transactio" + "nce\0225\n\007purpose\030\n \001(\0162\033.wallet.Transactio" +
"n.Purpose:\007UNKNOWN\022+\n\rexchange_rate\030\014 \001(" + "n.Purpose:\007UNKNOWN\022+\n\rexchange_rate\030\014 \001(" +
"\0132\024.wallet.ExchangeRate\"Y\n\004Pool\022\013\n\007UNSPE" + "\0132\024.wallet.ExchangeRate\022\014\n\004memo\030\r \001(\t\"Y\n" +
"NT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n\004DEAD\020\n\022" + "\004Pool\022\013\n\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIV" +
"\013\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE\020\022\"\224\001\n\007P" + "E\020\002\022\010\n\004DEAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_IN" +
"urpose\022\013\n\007UNKNOWN\020\000\022\020\n\014USER_PAYMENT\020\001\022\020\n" + "ACTIVE\020\022\"\224\001\n\007Purpose\022\013\n\007UNKNOWN\020\000\022\020\n\014USE" +
"\014KEY_ROTATION\020\002\022\034\n\030ASSURANCE_CONTRACT_CL" + "R_PAYMENT\020\001\022\020\n\014KEY_ROTATION\020\002\022\034\n\030ASSURAN" +
"AIM\020\003\022\035\n\031ASSURANCE_CONTRACT_PLEDGE\020\004\022\033\n\027", "CE_CONTRACT_CLAIM\020\003\022\035\n\031ASSURANCE_CONTRAC",
"ASSURANCE_CONTRACT_STUB\020\005\"N\n\020ScryptParam" + "T_PLEDGE\020\004\022\033\n\027ASSURANCE_CONTRACT_STUB\020\005\"" +
"eters\022\014\n\004salt\030\001 \002(\014\022\020\n\001n\030\002 \001(\003:\00516384\022\014\n" + "N\n\020ScryptParameters\022\014\n\004salt\030\001 \002(\014\022\020\n\001n\030\002" +
"\001r\030\003 \001(\005:\0018\022\014\n\001p\030\004 \001(\005:\0011\"8\n\tExtension\022\n" + " \001(\003:\00516384\022\014\n\001r\030\003 \001(\005:\0018\022\014\n\001p\030\004 \001(\005:\0011\"" +
"\n\002id\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\022\021\n\tmandatory\030\003 " + "8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\022\021" +
"\002(\010\" \n\003Tag\022\013\n\003tag\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\"5\n" + "\n\tmandatory\030\003 \002(\010\" \n\003Tag\022\013\n\003tag\030\001 \002(\t\022\014\n" +
"\021TransactionSigner\022\022\n\nclass_name\030\001 \002(\t\022\014" + "\004data\030\002 \002(\014\"5\n\021TransactionSigner\022\022\n\nclas" +
"\n\004data\030\002 \001(\014\"\351\004\n\006Wallet\022\032\n\022network_ident" + "s_name\030\001 \002(\t\022\014\n\004data\030\002 \001(\014\"\351\004\n\006Wallet\022\032\n" +
"ifier\030\001 \002(\t\022\034\n\024last_seen_block_hash\030\002 \001(" + "\022network_identifier\030\001 \002(\t\022\034\n\024last_seen_b" +
"\014\022\036\n\026last_seen_block_height\030\014 \001(\r\022!\n\031las" + "lock_hash\030\002 \001(\014\022\036\n\026last_seen_block_heigh" +
"t_seen_block_time_secs\030\016 \001(\003\022\030\n\003key\030\003 \003(", "t\030\014 \001(\r\022!\n\031last_seen_block_time_secs\030\016 \001",
"\0132\013.wallet.Key\022(\n\013transaction\030\004 \003(\0132\023.wa" + "(\003\022\030\n\003key\030\003 \003(\0132\013.wallet.Key\022(\n\013transact" +
"llet.Transaction\022&\n\016watched_script\030\017 \003(\013" + "ion\030\004 \003(\0132\023.wallet.Transaction\022&\n\016watche" +
"2\016.wallet.Script\022C\n\017encryption_type\030\005 \001(" + "d_script\030\017 \003(\0132\016.wallet.Script\022C\n\017encryp" +
"\0162\035.wallet.Wallet.EncryptionType:\013UNENCR" + "tion_type\030\005 \001(\0162\035.wallet.Wallet.Encrypti" +
"YPTED\0227\n\025encryption_parameters\030\006 \001(\0132\030.w" + "onType:\013UNENCRYPTED\0227\n\025encryption_parame" +
"allet.ScryptParameters\022\022\n\007version\030\007 \001(\005:" + "ters\030\006 \001(\0132\030.wallet.ScryptParameters\022\022\n\007" +
"\0011\022$\n\textension\030\n \003(\0132\021.wallet.Extension" + "version\030\007 \001(\005:\0011\022$\n\textension\030\n \003(\0132\021.wa" +
"\022\023\n\013description\030\013 \001(\t\022\031\n\021key_rotation_ti" + "llet.Extension\022\023\n\013description\030\013 \001(\t\022\031\n\021k" +
"me\030\r \001(\004\022\031\n\004tags\030\020 \003(\0132\013.wallet.Tag\0226\n\023t" + "ey_rotation_time\030\r \001(\004\022\031\n\004tags\030\020 \003(\0132\013.w" +
"ransaction_signers\030\021 \003(\0132\031.wallet.Transa", "allet.Tag\0226\n\023transaction_signers\030\021 \003(\0132\031",
"ctionSigner\";\n\016EncryptionType\022\017\n\013UNENCRY" + ".wallet.TransactionSigner\";\n\016EncryptionT" +
"PTED\020\001\022\030\n\024ENCRYPTED_SCRYPT_AES\020\002\"R\n\014Exch" + "ype\022\017\n\013UNENCRYPTED\020\001\022\030\n\024ENCRYPTED_SCRYPT" +
"angeRate\022\022\n\ncoin_value\030\001 \002(\003\022\022\n\nfiat_val" + "_AES\020\002\"R\n\014ExchangeRate\022\022\n\ncoin_value\030\001 \002" +
"ue\030\002 \002(\003\022\032\n\022fiat_currency_code\030\003 \002(\tB\035\n\023" + "(\003\022\022\n\nfiat_value\030\002 \002(\003\022\032\n\022fiat_currency_" +
"org.bitcoinj.walletB\006Protos" "code\030\003 \002(\tB\035\n\023org.bitcoinj.walletB\006Proto" +
"s"
}; };
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() {
@ -18400,7 +18617,7 @@ public final class Protos {
internal_static_wallet_Transaction_fieldAccessorTable = new internal_static_wallet_Transaction_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable( com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_wallet_Transaction_descriptor, internal_static_wallet_Transaction_descriptor,
new java.lang.String[] { "Version", "Hash", "Pool", "LockTime", "UpdatedAt", "TransactionInput", "TransactionOutput", "BlockHash", "BlockRelativityOffsets", "Confidence", "Purpose", "ExchangeRate", }); new java.lang.String[] { "Version", "Hash", "Pool", "LockTime", "UpdatedAt", "TransactionInput", "TransactionOutput", "BlockHash", "BlockRelativityOffsets", "Confidence", "Purpose", "ExchangeRate", "Memo", });
internal_static_wallet_ScryptParameters_descriptor = internal_static_wallet_ScryptParameters_descriptor =
getDescriptor().getMessageTypes().get(9); getDescriptor().getMessageTypes().get(9);
internal_static_wallet_ScryptParameters_fieldAccessorTable = new internal_static_wallet_ScryptParameters_fieldAccessorTable = new

View File

@ -2614,4 +2614,13 @@ public class WalletTest extends TestWithWallet {
wallet.completeTx(sendRequest); wallet.completeTx(sendRequest);
assertEquals(sendRequest.exchangeRate, sendRequest.tx.getExchangeRate()); assertEquals(sendRequest.exchangeRate, sendRequest.tx.getExchangeRate());
} }
@Test
public void sendRequestMemo() throws Exception {
receiveATransaction(wallet, myAddress);
SendRequest sendRequest = SendRequest.to(myAddress, Coin.COIN);
sendRequest.memo = "memo";
wallet.completeTx(sendRequest);
assertEquals(sendRequest.memo, sendRequest.tx.getMemo());
}
} }

View File

@ -266,7 +266,11 @@ message Transaction {
// Exchange rate that was valid when the transaction was sent. // Exchange rate that was valid when the transaction was sent.
optional ExchangeRate exchange_rate = 12; optional ExchangeRate exchange_rate = 12;
// Next tag: 13 // Memo of the transaction. It can be used to record the memo of the payment request that initiated the
// transaction.
optional string memo = 13;
// Next tag: 14
} }
/** The parameters used in the scrypt key derivation function. /** The parameters used in the scrypt key derivation function.