Teach SendRequest and Wallet to send to native segwit addresses.

WalletTool and FakeTxBuilder can do it, too.
This commit is contained in:
Andreas Schildbach 2018-02-23 20:03:27 +01:00
parent 2c768bfe07
commit 52afdc629e
8 changed files with 44 additions and 25 deletions

View File

@ -900,7 +900,7 @@ public class Block extends Message {
* 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);
}
@ -910,7 +910,7 @@ public class Block extends Message {
*
* @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) {
@ -958,17 +958,17 @@ public class Block extends Message {
}
@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);
}

View File

@ -884,7 +884,7 @@ public class Transaction extends ChildMessage {
/**
* 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));
}

View File

@ -84,9 +84,9 @@ public class TransactionOutput extends ChildMessage {
/**
* 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());
}

View File

@ -24,6 +24,7 @@ import java.math.BigInteger;
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;
@ -163,7 +164,7 @@ public class 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");
@ -177,7 +178,7 @@ public class SendRequest {
*
* <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) {
@ -194,7 +195,7 @@ public class SendRequest {
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");

View File

@ -25,6 +25,7 @@ import com.google.common.util.concurrent.*;
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;
@ -3779,11 +3780,11 @@ public class Wallet extends BaseTaggableObject
* {@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>
@ -3805,7 +3806,7 @@ public class Wallet extends BaseTaggableObject
* @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;
@ -3864,7 +3865,7 @@ public class Wallet extends BaseTaggableObject
* @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);
}

View File

@ -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;
@ -64,7 +80,7 @@ public class FakeTxBuilder {
* 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);
@ -86,7 +102,7 @@ public class FakeTxBuilder {
* 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);
@ -122,7 +138,7 @@ public class FakeTxBuilder {
* 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()));
}
@ -151,7 +167,7 @@ public class FakeTxBuilder {
* 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);
@ -200,7 +216,7 @@ public class FakeTxBuilder {
* 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());
@ -290,7 +306,7 @@ public class FakeTxBuilder {
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;
@ -307,7 +323,7 @@ public class FakeTxBuilder {
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) {

View File

@ -680,7 +680,7 @@ public class WalletTool {
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 {
@ -700,7 +700,7 @@ public class WalletTool {
addr = null;
} else {
// Treat as an address.
addr = LegacyAddress.fromBase58(params, destination);
addr = Address.fromString(params, destination);
key = null;
}
}

View File

@ -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.