Skip to content

Commit

Permalink
Teach SendRequest and Wallet to send to native segwit addresses.
Browse files Browse the repository at this point in the history
WalletTool and FakeTxBuilder can do it, too.
  • Loading branch information
Andreas Schildbach committed Mar 4, 2018
1 parent 2c768bf commit 52afdc6
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 25 deletions.
10 changes: 5 additions & 5 deletions core/src/main/java/org/bitcoinj/core/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ void addCoinbaseTransaction(byte[] pubKeyTo, Coin value, final int height) {
* Returns a solved block that builds on top of this one. This exists for unit tests.
*/
@VisibleForTesting
public Block createNextBlock(LegacyAddress to, long version, long time, int blockHeight) {
public Block createNextBlock(Address to, long version, long time, int blockHeight) {
return createNextBlock(to, version, null, time, pubkeyForTesting, FIFTY_COINS, blockHeight);
}

Expand All @@ -910,7 +910,7 @@ public Block createNextBlock(LegacyAddress to, long version, long time, int bloc
*
* @param height block height, if known, or -1 otherwise.
*/
Block createNextBlock(@Nullable final LegacyAddress to, final long version,
Block createNextBlock(@Nullable final Address to, final long version,
@Nullable TransactionOutPoint prevOut, final long time,
final byte[] pubKey, final Coin coinbaseValue,
final int height) {
Expand Down Expand Up @@ -958,17 +958,17 @@ Block createNextBlock(@Nullable final LegacyAddress to, final long version,
}

@VisibleForTesting
public Block createNextBlock(@Nullable LegacyAddress to, TransactionOutPoint prevOut) {
public Block createNextBlock(@Nullable Address to, TransactionOutPoint prevOut) {
return createNextBlock(to, BLOCK_VERSION_GENESIS, prevOut, getTimeSeconds() + 5, pubkeyForTesting, FIFTY_COINS, BLOCK_HEIGHT_UNKNOWN);
}

@VisibleForTesting
public Block createNextBlock(@Nullable LegacyAddress to, Coin value) {
public Block createNextBlock(@Nullable Address to, Coin value) {
return createNextBlock(to, BLOCK_VERSION_GENESIS, null, getTimeSeconds() + 5, pubkeyForTesting, value, BLOCK_HEIGHT_UNKNOWN);
}

@VisibleForTesting
public Block createNextBlock(@Nullable LegacyAddress to) {
public Block createNextBlock(@Nullable Address to) {
return createNextBlock(to, FIFTY_COINS);
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/bitcoinj/core/Transaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@ public TransactionOutput addOutput(TransactionOutput to) {
/**
* Creates an output based on the given address and value, adds it to this transaction, and returns the new output.
*/
public TransactionOutput addOutput(Coin value, LegacyAddress address) {
public TransactionOutput addOutput(Coin value, Address address) {
return addOutput(new TransactionOutput(params, this, value, address));
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/org/bitcoinj/core/TransactionOutput.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ public TransactionOutput(NetworkParameters params, @Nullable Transaction parent,
/**
* Creates an output that sends 'value' to the given address (public key hash). The amount should be created with
* something like {@link Coin#valueOf(int, int)}. Typically you would use
* {@link Transaction#addOutput(Coin, LegacyAddress)} instead of creating a TransactionOutput directly.
* {@link Transaction#addOutput(Coin, Address)} instead of creating a TransactionOutput directly.
*/
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, Coin value, LegacyAddress to) {
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, Coin value, Address to) {
this(params, parent, value, ScriptBuilder.createOutputScript(to).getProgram());
}

Expand Down
7 changes: 4 additions & 3 deletions core/src/main/java/org/bitcoinj/wallet/SendRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Date;

import org.bitcoin.protocols.payments.Protos.PaymentDetails;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.LegacyAddress;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Context;
Expand Down Expand Up @@ -163,7 +164,7 @@ private SendRequest() {}
* <p>Be very careful when value is smaller than {@link Transaction#MIN_NONDUST_OUTPUT} as the transaction will
* likely be rejected by the network in this case.</p>
*/
public static SendRequest to(LegacyAddress destination, Coin value) {
public static SendRequest to(Address destination, Coin value) {
SendRequest req = new SendRequest();
final NetworkParameters parameters = destination.getParameters();
checkNotNull(parameters, "Address is for an unknown network");
Expand All @@ -177,7 +178,7 @@ public static SendRequest to(LegacyAddress destination, Coin value) {
*
* <p>Be careful to check the output's value is reasonable using
* {@link TransactionOutput#getMinNonDustValue(Coin)} afterwards or you risk having the transaction
* rejected by the network. Note that using {@link SendRequest#to(LegacyAddress, Coin)} will result
* rejected by the network. Note that using {@link SendRequest#to(Address, Coin)} will result
* in a smaller output, and thus the ability to use a smaller output value without rejection.</p>
*/
public static SendRequest to(NetworkParameters params, ECKey destination, Coin value) {
Expand All @@ -194,7 +195,7 @@ public static SendRequest forTx(Transaction tx) {
return req;
}

public static SendRequest emptyWallet(LegacyAddress destination) {
public static SendRequest emptyWallet(Address destination) {
SendRequest req = new SendRequest();
final NetworkParameters parameters = destination.getParameters();
checkNotNull(parameters, "Address is for an unknown network");
Expand Down
9 changes: 5 additions & 4 deletions core/src/main/java/org/bitcoinj/wallet/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.google.protobuf.*;
import net.jcip.annotations.*;
import org.bitcoinj.core.listeners.*;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.AbstractBlockChain;
import org.bitcoinj.core.LegacyAddress;
import org.bitcoinj.core.BlockChain;
Expand Down Expand Up @@ -3779,11 +3780,11 @@ public enum MissingSigsMode {
* {@link Wallet#currentChangeAddress()}, so you must have added at least one key.</p>
*
* <p>If you just want to send money quickly, you probably want
* {@link Wallet#sendCoins(TransactionBroadcaster, LegacyAddress, Coin)} instead. That will create the sending
* {@link Wallet#sendCoins(TransactionBroadcaster, Address, Coin)} instead. That will create the sending
* transaction, commit to the wallet and broadcast it to the network all in one go. This method is lower level
* and lets you see the proposed transaction before anything is done with it.</p>
*
* <p>This is a helper method that is equivalent to using {@link SendRequest#to(LegacyAddress, Coin)}
* <p>This is a helper method that is equivalent to using {@link SendRequest#to(Address, Coin)}
* followed by {@link Wallet#completeTx(SendRequest)} and returning the requests transaction object.
* Note that this means a fee may be automatically added if required, if you want more control over the process,
* just do those two steps yourself.</p>
Expand All @@ -3805,7 +3806,7 @@ public enum MissingSigsMode {
* @throws ExceededMaxTransactionSize if the resultant transaction is too big for Bitcoin to process.
* @throws MultipleOpReturnRequested if there is more than one OP_RETURN output for the resultant transaction.
*/
public Transaction createSend(LegacyAddress address, Coin value) throws InsufficientMoneyException {
public Transaction createSend(Address address, Coin value) throws InsufficientMoneyException {
SendRequest req = SendRequest.to(address, value);
if (params.getId().equals(NetworkParameters.ID_UNITTESTNET))
req.shuffleOutputs = false;
Expand Down Expand Up @@ -3864,7 +3865,7 @@ public Transaction sendCoinsOffline(SendRequest request) throws InsufficientMone
* @throws ExceededMaxTransactionSize if the resultant transaction is too big for Bitcoin to process.
* @throws MultipleOpReturnRequested if there is more than one OP_RETURN output for the resultant transaction.
*/
public SendResult sendCoins(TransactionBroadcaster broadcaster, LegacyAddress to, Coin value) throws InsufficientMoneyException {
public SendResult sendCoins(TransactionBroadcaster broadcaster, Address to, Coin value) throws InsufficientMoneyException {
SendRequest request = SendRequest.to(to, value);
return sendCoins(broadcaster, request);
}
Expand Down
32 changes: 24 additions & 8 deletions core/src/test/java/org/bitcoinj/testing/FakeTxBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,23 @@

package org.bitcoinj.testing;

import org.bitcoinj.core.*;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Block;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.LegacyAddress;
import org.bitcoinj.core.MessageSerializer;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.ProtocolException;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.StoredBlock;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutPoint;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.Utils;
import org.bitcoinj.core.VerificationException;
import org.bitcoinj.crypto.TransactionSignature;
import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.store.BlockStore;
Expand Down Expand Up @@ -64,7 +80,7 @@ public static Transaction createFakeCoinbaseTx(final NetworkParameters params) {
* Create a fake TX of sufficient realism to exercise the unit tests. Two outputs, one to us, one to somewhere
* else to simulate change. There is one random input.
*/
public static Transaction createFakeTxWithChangeAddress(NetworkParameters params, Coin value, LegacyAddress to, LegacyAddress changeOutput) {
public static Transaction createFakeTxWithChangeAddress(NetworkParameters params, Coin value, Address to, Address changeOutput) {
Transaction t = new Transaction(params);
TransactionOutput outputToMe = new TransactionOutput(params, t, value, to);
t.addOutput(outputToMe);
Expand All @@ -86,7 +102,7 @@ public static Transaction createFakeTxWithChangeAddress(NetworkParameters params
* Create a fake TX for unit tests, for use with unit tests that need greater control. One outputs, 2 random inputs,
* split randomly to create randomness.
*/
public static Transaction createFakeTxWithoutChangeAddress(NetworkParameters params, Coin value, LegacyAddress to) {
public static Transaction createFakeTxWithoutChangeAddress(NetworkParameters params, Coin value, Address to) {
Transaction t = new Transaction(params);
TransactionOutput outputToMe = new TransactionOutput(params, t, value, to);
t.addOutput(outputToMe);
Expand Down Expand Up @@ -122,7 +138,7 @@ public static Transaction createFakeTxWithoutChangeAddress(NetworkParameters par
* Create a fake TX of sufficient realism to exercise the unit tests. Two outputs, one to us, one to somewhere
* else to simulate change. There is one random input.
*/
public static Transaction createFakeTx(NetworkParameters params, Coin value, LegacyAddress to) {
public static Transaction createFakeTx(NetworkParameters params, Coin value, Address to) {
return createFakeTxWithChangeAddress(params, value, to, LegacyAddress.fromKey(params, new ECKey()));
}

Expand Down Expand Up @@ -151,7 +167,7 @@ public static Transaction createFakeTx(NetworkParameters params, Coin value, ECK
* Transaction[0] is a feeder transaction, supplying BTC to Transaction[1]
*/
public static Transaction[] createFakeTx(NetworkParameters params, Coin value,
LegacyAddress to, LegacyAddress from) {
Address to, Address from) {
// Create fake TXes of sufficient realism to exercise the unit tests. This transaction send BTC from the
// from address, to the to address with to one to somewhere else to simulate change.
Transaction t = new Transaction(params);
Expand Down Expand Up @@ -200,7 +216,7 @@ public static class DoubleSpends {
* Creates two transactions that spend the same (fake) output. t1 spends to "to". t2 spends somewhere else.
* The fake output goes to the same address as t2.
*/
public static DoubleSpends createFakeDoubleSpendTxns(NetworkParameters params, LegacyAddress to) {
public static DoubleSpends createFakeDoubleSpendTxns(NetworkParameters params, Address to) {
DoubleSpends doubleSpends = new DoubleSpends();
Coin value = COIN;
LegacyAddress someBadGuy = LegacyAddress.fromKey(params, new ECKey());
Expand Down Expand Up @@ -290,7 +306,7 @@ public static BlockPair createFakeBlock(BlockStore blockStore, Transaction... tr
return createFakeBlock(blockStore, Block.BLOCK_VERSION_GENESIS, Utils.currentTimeSeconds(), 0, transactions);
}

public static Block makeSolvedTestBlock(BlockStore blockStore, LegacyAddress coinsTo) throws BlockStoreException {
public static Block makeSolvedTestBlock(BlockStore blockStore, Address coinsTo) throws BlockStoreException {
Block b = blockStore.getChainHead().getHeader().createNextBlock(coinsTo);
b.solve();
return b;
Expand All @@ -307,7 +323,7 @@ public static Block makeSolvedTestBlock(Block prev, Transaction... transactions)
return b;
}

public static Block makeSolvedTestBlock(Block prev, LegacyAddress to, Transaction... transactions) throws BlockStoreException {
public static Block makeSolvedTestBlock(Block prev, Address to, Transaction... transactions) throws BlockStoreException {
Block b = prev.createNextBlock(to);
// Coinbase tx already exists.
for (Transaction tx : transactions) {
Expand Down
4 changes: 2 additions & 2 deletions tools/src/main/java/org/bitcoinj/tools/WalletTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ private static void send(List<String> outputs, Coin feePerKb, String lockTimeStr

static class OutputSpec {
public final Coin value;
public final LegacyAddress addr;
public final Address addr;
public final ECKey key;

public OutputSpec(String spec) throws IllegalArgumentException {
Expand All @@ -700,7 +700,7 @@ public OutputSpec(String spec) throws IllegalArgumentException {
addr = null;
} else {
// Treat as an address.
addr = LegacyAddress.fromBase58(params, destination);
addr = Address.fromString(params, destination);
key = null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Usage: wallet-tool --flags action-name
You can repeat --output=address:value multiple times.
There is a magic value ALL which empties the wallet to that address, e.g.:
--output=1GthXFQMktFLWdh5EPNGqbq3H6WdG8zsWj:ALL
The output destination can also be a native segwit address.
If the output destination starts with 04 and is 65 or 33 bytes long it will be
treated as a public key instead of an address and the send will use
<key> CHECKSIG as the script.
Expand Down

0 comments on commit 52afdc6

Please sign in to comment.