mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-03-10 17:26:28 +01:00
Support for applications recording exchange rate that was valid when transaction was sent. Use the new SendRequest.exchangeRate register.
Includes a test.
This commit is contained in:
parent
d9be6a62d2
commit
5be769d4ca
6 changed files with 1159 additions and 32 deletions
|
@ -22,6 +22,7 @@ import com.google.bitcoin.crypto.TransactionSignature;
|
||||||
import com.google.bitcoin.script.Script;
|
import com.google.bitcoin.script.Script;
|
||||||
import com.google.bitcoin.script.ScriptBuilder;
|
import com.google.bitcoin.script.ScriptBuilder;
|
||||||
import com.google.bitcoin.script.ScriptOpCodes;
|
import com.google.bitcoin.script.ScriptOpCodes;
|
||||||
|
import com.google.bitcoin.utils.ExchangeRate;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
import com.google.common.primitives.Longs;
|
import com.google.common.primitives.Longs;
|
||||||
|
@ -152,6 +153,13 @@ public class Transaction extends ChildMessage implements Serializable {
|
||||||
|
|
||||||
private Purpose purpose = Purpose.UNKNOWN;
|
private Purpose purpose = Purpose.UNKNOWN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This field can be used by applications to record the exchange rate that was valid when the transaction happened.
|
||||||
|
* It's optional.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private ExchangeRate exchangeRate;
|
||||||
|
|
||||||
public Transaction(NetworkParameters params) {
|
public Transaction(NetworkParameters params) {
|
||||||
super(params);
|
super(params);
|
||||||
version = 1;
|
version = 1;
|
||||||
|
@ -1259,4 +1267,19 @@ public class Transaction extends ChildMessage implements Serializable {
|
||||||
public void setPurpose(Purpose purpose) {
|
public void setPurpose(Purpose purpose) {
|
||||||
this.purpose = purpose;
|
this.purpose = purpose;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for {@link #exchangeRate}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public ExchangeRate getExchangeRate() {
|
||||||
|
return exchangeRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter for {@link #exchangeRate}.
|
||||||
|
*/
|
||||||
|
public void setExchangeRate(ExchangeRate exchangeRate) {
|
||||||
|
this.exchangeRate = exchangeRate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import com.google.bitcoin.signers.TransactionSigner;
|
||||||
import com.google.bitcoin.store.UnreadableWalletException;
|
import com.google.bitcoin.store.UnreadableWalletException;
|
||||||
import com.google.bitcoin.store.WalletProtobufSerializer;
|
import com.google.bitcoin.store.WalletProtobufSerializer;
|
||||||
import com.google.bitcoin.utils.BaseTaggableObject;
|
import com.google.bitcoin.utils.BaseTaggableObject;
|
||||||
|
import com.google.bitcoin.utils.ExchangeRate;
|
||||||
import com.google.bitcoin.utils.ListenerRegistration;
|
import com.google.bitcoin.utils.ListenerRegistration;
|
||||||
import com.google.bitcoin.utils.Threading;
|
import com.google.bitcoin.utils.Threading;
|
||||||
import com.google.bitcoin.wallet.*;
|
import com.google.bitcoin.wallet.*;
|
||||||
|
@ -3010,6 +3011,11 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
|
||||||
*/
|
*/
|
||||||
public boolean useDummySignatures = true;
|
public boolean useDummySignatures = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If not null, this exchange rate is recorded with the transaction during completion.
|
||||||
|
*/
|
||||||
|
public ExchangeRate exchangeRate = 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;
|
||||||
|
|
||||||
|
@ -3375,6 +3381,8 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
|
||||||
// transaction lists more appropriately, especially when the wallet starts to generate transactions itself
|
// transaction lists more appropriately, especially when the wallet starts to generate transactions itself
|
||||||
// for internal purposes.
|
// for internal purposes.
|
||||||
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.
|
||||||
|
req.tx.setExchangeRate(req.exchangeRate);
|
||||||
req.completed = true;
|
req.completed = true;
|
||||||
req.fee = calculatedFee;
|
req.fee = calculatedFee;
|
||||||
log.info(" completed: {}", req.tx);
|
log.info(" completed: {}", req.tx);
|
||||||
|
|
|
@ -24,6 +24,8 @@ import com.google.bitcoin.crypto.KeyCrypterScrypt;
|
||||||
import com.google.bitcoin.script.Script;
|
import com.google.bitcoin.script.Script;
|
||||||
import com.google.bitcoin.signers.LocalTransactionSigner;
|
import com.google.bitcoin.signers.LocalTransactionSigner;
|
||||||
import com.google.bitcoin.signers.TransactionSigner;
|
import com.google.bitcoin.signers.TransactionSigner;
|
||||||
|
import com.google.bitcoin.utils.ExchangeRate;
|
||||||
|
import com.google.bitcoin.utils.Fiat;
|
||||||
import com.google.bitcoin.wallet.KeyChainGroup;
|
import com.google.bitcoin.wallet.KeyChainGroup;
|
||||||
import com.google.bitcoin.wallet.WalletTransaction;
|
import com.google.bitcoin.wallet.WalletTransaction;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
@ -290,6 +292,14 @@ public class WalletProtobufSerializer {
|
||||||
throw new RuntimeException("New tx purpose serialization not implemented.");
|
throw new RuntimeException("New tx purpose serialization not implemented.");
|
||||||
}
|
}
|
||||||
txBuilder.setPurpose(purpose);
|
txBuilder.setPurpose(purpose);
|
||||||
|
|
||||||
|
ExchangeRate exchangeRate = tx.getExchangeRate();
|
||||||
|
if (exchangeRate != null) {
|
||||||
|
Protos.ExchangeRate.Builder exchangeRateBuilder = Protos.ExchangeRate.newBuilder()
|
||||||
|
.setCoinValue(exchangeRate.coin.value).setFiatValue(exchangeRate.fiat.value)
|
||||||
|
.setFiatCurrencyCode(exchangeRate.fiat.currencyCode);
|
||||||
|
txBuilder.setExchangeRate(exchangeRateBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
return txBuilder.build();
|
return txBuilder.build();
|
||||||
}
|
}
|
||||||
|
@ -576,6 +586,12 @@ public class WalletProtobufSerializer {
|
||||||
tx.setPurpose(Transaction.Purpose.USER_PAYMENT);
|
tx.setPurpose(Transaction.Purpose.USER_PAYMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (txProto.hasExchangeRate()) {
|
||||||
|
Protos.ExchangeRate exchangeRateProto = txProto.getExchangeRate();
|
||||||
|
tx.setExchangeRate(new ExchangeRate(Coin.valueOf(exchangeRateProto.getCoinValue()), Fiat.valueOf(
|
||||||
|
exchangeRateProto.getFiatCurrencyCode(), exchangeRateProto.getFiatValue())));
|
||||||
|
}
|
||||||
|
|
||||||
// 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))
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -28,6 +28,8 @@ import com.google.bitcoin.testing.FakeTxBuilder;
|
||||||
import com.google.bitcoin.testing.MockTransactionBroadcaster;
|
import com.google.bitcoin.testing.MockTransactionBroadcaster;
|
||||||
import com.google.bitcoin.testing.NopTransactionSigner;
|
import com.google.bitcoin.testing.NopTransactionSigner;
|
||||||
import com.google.bitcoin.testing.TestWithWallet;
|
import com.google.bitcoin.testing.TestWithWallet;
|
||||||
|
import com.google.bitcoin.utils.ExchangeRate;
|
||||||
|
import com.google.bitcoin.utils.Fiat;
|
||||||
import com.google.bitcoin.utils.Threading;
|
import com.google.bitcoin.utils.Threading;
|
||||||
import com.google.bitcoin.wallet.*;
|
import com.google.bitcoin.wallet.*;
|
||||||
import com.google.bitcoin.wallet.WalletTransaction.Pool;
|
import com.google.bitcoin.wallet.WalletTransaction.Pool;
|
||||||
|
@ -2555,4 +2557,12 @@ public class WalletTest extends TestWithWallet {
|
||||||
assertTrue(wallet.getTransactionSigners().get(1).isReady());
|
assertTrue(wallet.getTransactionSigners().get(1).isReady());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sendRequestExchangeRate() throws Exception {
|
||||||
|
receiveATransaction(wallet, myAddress);
|
||||||
|
SendRequest sendRequest = SendRequest.to(myAddress, Coin.COIN);
|
||||||
|
sendRequest.exchangeRate = new ExchangeRate(Fiat.parseFiat("EUR", "500"));
|
||||||
|
wallet.completeTx(sendRequest);
|
||||||
|
assertEquals(sendRequest.exchangeRate, sendRequest.tx.getExchangeRate());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -263,7 +263,10 @@ message Transaction {
|
||||||
}
|
}
|
||||||
optional Purpose purpose = 10 [default = UNKNOWN];
|
optional Purpose purpose = 10 [default = UNKNOWN];
|
||||||
|
|
||||||
// Next tag: 12
|
// Exchange rate that was valid when the transaction was sent.
|
||||||
|
optional ExchangeRate exchange_rate = 12;
|
||||||
|
|
||||||
|
// Next tag: 13
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The parameters used in the scrypt key derivation function.
|
/** The parameters used in the scrypt key derivation function.
|
||||||
|
@ -366,3 +369,15 @@ message Wallet {
|
||||||
|
|
||||||
// Next tag: 18
|
// Next tag: 18
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An exchange rate between Bitcoin and some fiat currency. */
|
||||||
|
message ExchangeRate {
|
||||||
|
// This much of satoshis (1E-8 fractions)…
|
||||||
|
required int64 coin_value = 1;
|
||||||
|
// …is worth this much of fiat (1E-4 fractions).
|
||||||
|
required int64 fiat_value = 2;
|
||||||
|
// ISO 4217 currency code (if available) of the fiat currency.
|
||||||
|
required string fiat_currency_code = 3;
|
||||||
|
|
||||||
|
// Next tag: 4
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue