Use BitcoinNetwork vs. BitcoinJ's NetworkParameters

BitcoinNetwork now supports a #getParameters method that returns the
BitcoinJ NetworkParameters instance associated with the given
BitcoinNetwork enum label (e.g. TESTNET.getParameters() returns
TestNet3Params, etc).

BitcoinModule#BITCOIN_NETWORK_KEY and #DEFAULT_BITCOIN_NETWORK have been
moved to BitcoinNetwork#KEY and BitcoinNetwork#DEFAULT respectively.

Customzing the bitcoin network to use on the command line has been
improved. Values may be upper or lower case (e.g. "testnet", "TESTNET"),
and the value passed is converted to the correct BitcoinNetwork enum
value with the new EnumValueConverter class.

Finally, a BitcoinNetwork instance is now made available for injection
by BitcoinModule as opposed to binding a NetworkParameters instance. All
injection targets (constructors) throughout the codebase have been
updated to reflect this change, and the result is cleaner, enum-based
processing everywhere possible. And where it's necessary to drop down to
BitcoinJ's NetworkParameters, that's easy to do by calling
BitcoinNetwork#getParameters.
This commit is contained in:
Chris Beams 2014-11-13 10:34:09 +01:00
parent 8d70e23ba5
commit b911cd2a95
No known key found for this signature in database
GPG Key ID: 3D214F8F5BC5ED73
8 changed files with 132 additions and 58 deletions

View File

@ -19,15 +19,15 @@ package io.bitsquare.app.gui;
import io.bitsquare.app.BitsquareEnvironment;
import io.bitsquare.app.BitsquareExecutable;
import io.bitsquare.btc.BitcoinModule;
import io.bitsquare.btc.BitcoinNetwork;
import io.bitsquare.network.BootstrapNodes;
import io.bitsquare.network.Node;
import io.bitsquare.util.joptsimple.EnumValueConverter;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import static io.bitsquare.app.BitsquareEnvironment.*;
import static io.bitsquare.btc.BitcoinModule.BITCOIN_NETWORK_KEY;
import static io.bitsquare.msg.tomp2p.TomP2PMessageModule.*;
import static io.bitsquare.network.Node.*;
@ -44,8 +44,10 @@ public class BitsquareAppMain extends BitsquareExecutable {
parser.accepts(APP_DATA_DIR_KEY, "Application data directory").withRequiredArg()
.defaultsTo(DEFAULT_APP_DATA_DIR);
parser.accepts(NAME_KEY, "Name of this node").withRequiredArg();
parser.accepts(BITCOIN_NETWORK_KEY).withRequiredArg().defaultsTo(BitcoinModule.DEFAULT_BITCOIN_NETWORK);
parser.accepts(PORT_KEY, "Port to listen on").withRequiredArg().ofType(int.class).defaultsTo(Node.DEFAULT_PORT);
parser.accepts(BitcoinNetwork.KEY).withRequiredArg().ofType(BitcoinNetwork.class)
.withValuesConvertedBy(new EnumValueConverter(BitcoinNetwork.class))
.defaultsTo(BitcoinNetwork.DEFAULT);
parser.accepts(BOOTSTRAP_NODE_NAME_KEY).withRequiredArg().defaultsTo(BootstrapNodes.DEFAULT.getName());
parser.accepts(BOOTSTRAP_NODE_IP_KEY).withRequiredArg().defaultsTo(BootstrapNodes.DEFAULT.getIp());
parser.accepts(BOOTSTRAP_NODE_PORT_KEY).withRequiredArg().ofType(int.class)

View File

@ -34,8 +34,6 @@ import static com.google.inject.name.Names.named;
public class BitcoinModule extends BitsquareModule {
public static final String BITCOIN_NETWORK_KEY = "bitcoin.network";
public static final String DEFAULT_BITCOIN_NETWORK = BitcoinNetwork.TESTNET.toString();
public BitcoinModule(Environment env) {
super(env);
@ -43,7 +41,8 @@ public class BitcoinModule extends BitsquareModule {
@Override
protected void configure() {
bind(NetworkParameters.class).toInstance(network());
bind(BitcoinNetwork.class).toInstance(
env.getProperty(BitcoinNetwork.KEY, BitcoinNetwork.class, BitcoinNetwork.DEFAULT));
bind(FeePolicy.class).asEagerSingleton();
bindConstant().annotatedWith(named(UserAgent.NAME_KEY)).to(env.getRequiredProperty(UserAgent.NAME_KEY));
@ -63,21 +62,5 @@ public class BitcoinModule extends BitsquareModule {
protected void doClose(Injector injector) {
injector.getInstance(WalletService.class).shutDown();
}
private NetworkParameters network() {
BitcoinNetwork network = BitcoinNetwork.valueOf(
env.getProperty(BITCOIN_NETWORK_KEY, DEFAULT_BITCOIN_NETWORK).toUpperCase());
switch (network) {
case MAINNET:
return MainNetParams.get();
case TESTNET:
return TestNet3Params.get();
case REGTEST:
return RegTestParams.get();
default:
throw new IllegalArgumentException("Unknown bitcoin network: " + network);
}
}
}

View File

@ -17,6 +17,27 @@
package io.bitsquare.btc;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.params.RegTestParams;
import org.bitcoinj.params.TestNet3Params;
public enum BitcoinNetwork {
MAINNET, TESTNET, REGTEST;
MAINNET(MainNetParams.get()),
TESTNET(TestNet3Params.get()),
REGTEST(RegTestParams.get());
public static final String KEY = "bitcoin.network";
public static final BitcoinNetwork DEFAULT = TESTNET;
private final NetworkParameters parameters;
BitcoinNetwork(NetworkParameters parameters) {
this.parameters = parameters;
}
public NetworkParameters getParameters() {
return parameters;
}
}

View File

@ -20,11 +20,7 @@ package io.bitsquare.btc;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.params.RegTestParams;
import org.bitcoinj.params.TestNet3Params;
import javax.inject.Inject;
@ -49,28 +45,29 @@ public class FeePolicy {
// Not used at the moment
// private static final String registrationFeeAddress = "mvkDXt4QmN4Nq9dRUsRigBCaovde9nLkZR";
//
private static String createOfferFeeAddress;
private static String takeOfferFeeAddress;
private final NetworkParameters params;
private final BitcoinNetwork bitcoinNetwork;
@Inject
public FeePolicy(NetworkParameters params) {
this.params = params;
public FeePolicy(BitcoinNetwork bitcoinNetwork) {
this.bitcoinNetwork = bitcoinNetwork;
if (params.equals(TestNet3Params.get())) {
createOfferFeeAddress = "mmm8BdTcHoc5wi75RmiQYsJ2Tr1NoZmM84";
takeOfferFeeAddress = "mmm8BdTcHoc5wi75RmiQYsJ2Tr1NoZmM84";
}
else if (params.equals(MainNetParams.get())) {
// bitsquare donation address used for the moment...
createOfferFeeAddress = "1BVxNn3T12veSK6DgqwU4Hdn7QHcDDRag7";
takeOfferFeeAddress = "1BVxNn3T12veSK6DgqwU4Hdn7QHcDDRag7";
}
else if (params.equals(RegTestParams.get())) {
createOfferFeeAddress = "n2upbsaKAe4PD3cc4JfS7UCqPC5oNd7Ckg";
takeOfferFeeAddress = "n2upbsaKAe4PD3cc4JfS7UCqPC5oNd7Ckg";
switch (bitcoinNetwork) {
case TESTNET:
createOfferFeeAddress = "mmm8BdTcHoc5wi75RmiQYsJ2Tr1NoZmM84";
takeOfferFeeAddress = "mmm8BdTcHoc5wi75RmiQYsJ2Tr1NoZmM84";
break;
case MAINNET:
// bitsquare donation address used for the moment...
createOfferFeeAddress = "1BVxNn3T12veSK6DgqwU4Hdn7QHcDDRag7";
takeOfferFeeAddress = "1BVxNn3T12veSK6DgqwU4Hdn7QHcDDRag7";
break;
case REGTEST:
createOfferFeeAddress = "n2upbsaKAe4PD3cc4JfS7UCqPC5oNd7Ckg";
takeOfferFeeAddress = "n2upbsaKAe4PD3cc4JfS7UCqPC5oNd7Ckg";
break;
}
}
@ -89,7 +86,7 @@ public class FeePolicy {
//TODO get address form arbitrator list
public Address getAddressForCreateOfferFee() {
try {
return new Address(params, createOfferFeeAddress);
return new Address(bitcoinNetwork.getParameters(), createOfferFeeAddress);
} catch (AddressFormatException e) {
e.printStackTrace();
return null;
@ -99,7 +96,7 @@ public class FeePolicy {
//TODO get address form the intersection of both traders arbitrator lists
public Address getAddressForTakeOfferFee() {
try {
return new Address(params, takeOfferFeeAddress);
return new Address(bitcoinNetwork.getParameters(), takeOfferFeeAddress);
} catch (AddressFormatException e) {
e.printStackTrace();
return null;

View File

@ -123,10 +123,10 @@ public class WalletService {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public WalletService(NetworkParameters params, FeePolicy feePolicy, SignatureService signatureService,
public WalletService(BitcoinNetwork bitcoinNetwork, FeePolicy feePolicy, SignatureService signatureService,
Persistence persistence, UserAgent userAgent,
@Named(DIR_KEY) File walletDir, @Named(PREFIX_KEY) String walletPrefix) {
this.params = params;
this.params = bitcoinNetwork.getParameters();
this.feePolicy = feePolicy;
this.signatureService = signatureService;
this.persistence = persistence;

View File

@ -17,10 +17,9 @@
package io.bitsquare.gui.main.preferences.network;
import io.bitsquare.btc.BitcoinNetwork;
import io.bitsquare.network.ClientNode;
import org.bitcoinj.core.NetworkParameters;
import java.net.URL;
import java.util.ResourceBundle;
@ -33,20 +32,20 @@ import javafx.scene.control.*;
public class NetworkPreferencesViewCB implements Initializable {
private final NetworkParameters networkParameters;
private final String bitcoinNetworkValue;
private final ClientNode clientNode;
@FXML TextField bitcoinNetwork, connectionType, nodeAddress, bootstrapNodeAddress;
@Inject
public NetworkPreferencesViewCB(NetworkParameters networkParameters, ClientNode clientNode) {
this.networkParameters = networkParameters;
public NetworkPreferencesViewCB(BitcoinNetwork bitcoinNetwork, ClientNode clientNode) {
this.bitcoinNetworkValue = bitcoinNetwork.toString();
this.clientNode = clientNode;
}
@Override
public void initialize(URL url, ResourceBundle rb) {
bitcoinNetwork.setText(networkParameters.getId());
bitcoinNetwork.setText(bitcoinNetworkValue);
nodeAddress.setText(clientNode.getAddress().toString());
bootstrapNodeAddress.setText(clientNode.getBootstrapNodeAddress().toString());
connectionType.setText(clientNode.getConnectionType().toString());

View File

@ -17,9 +17,10 @@
package io.bitsquare.gui.util.validation;
import io.bitsquare.btc.BitcoinNetwork;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.NetworkParameters;
import javax.inject.Inject;
@ -33,7 +34,8 @@ import org.slf4j.LoggerFactory;
*/
public final class BtcAddressValidator extends InputValidator {
private static final Logger log = LoggerFactory.getLogger(BtcAddressValidator.class);
private final NetworkParameters networkParameters;
private final BitcoinNetwork bitcoinNetwork;
///////////////////////////////////////////////////////////////////////////////////////////
@ -41,8 +43,8 @@ public final class BtcAddressValidator extends InputValidator {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public BtcAddressValidator(NetworkParameters networkParameters) {
this.networkParameters = networkParameters;
public BtcAddressValidator(BitcoinNetwork bitcoinNetwork) {
this.bitcoinNetwork = bitcoinNetwork;
}
@ -67,7 +69,7 @@ public final class BtcAddressValidator extends InputValidator {
private ValidationResult validateBtcAddress(String input) {
try {
new Address(networkParameters, input);
new Address(bitcoinNetwork.getParameters(), input);
return new ValidationResult(true);
} catch (AddressFormatException e) {
return new ValidationResult(false, "Bitcoin address is a valid format");

View File

@ -0,0 +1,70 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.util.joptsimple;
import com.google.common.base.Enums;
import com.google.common.base.Optional;
import com.google.common.collect.Sets;
import java.util.Set;
import joptsimple.ValueConverter;
import static org.springframework.util.StringUtils.collectionToDelimitedString;
/**
* A {@link joptsimple.ValueConverter} that supports case-insensitive conversion from
* String to an enum label. Useful in conjunction with {@link joptsimple.ArgumentAcceptingOptionSpec#ofType(Class)}
* when the type in question is an enum.
*/
public class EnumValueConverter implements ValueConverter<Enum> {
private final Class<? extends Enum> enumType;
public EnumValueConverter(Class<? extends Enum> enumType) {
this.enumType = enumType;
}
/**
* Attempt to resolve an enum of the specified type by looking for a label with the
* given value, trying all case variations in the process.
* @return the matching enum label (if any)
* @throws IllegalArgumentException if no such label matching the given value is found.
*/
@Override
public Enum convert(String value) {
Set<String> candidates = Sets.newHashSet(value, value.toUpperCase(), value.toLowerCase());
for (String candidate : candidates) {
Optional<? extends Enum> result = Enums.getIfPresent(enumType, candidate);
if (result.isPresent())
return result.get();
}
throw new IllegalArgumentException(String.format(
"No enum constant %s.[%s]", enumType.getName(), collectionToDelimitedString(candidates, "|")));
}
@Override
public Class<? extends Enum> valueType() {
return enumType;
}
@Override
public String valuePattern() {
return null;
}
}