From b911cd2a95aa545aa033b9c14fc571c00d6e0b8c Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Thu, 13 Nov 2014 10:34:09 +0100 Subject: [PATCH] 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. --- .../bitsquare/app/gui/BitsquareAppMain.java | 8 ++- .../java/io/bitsquare/btc/BitcoinModule.java | 21 +----- .../java/io/bitsquare/btc/BitcoinNetwork.java | 23 +++++- src/main/java/io/bitsquare/btc/FeePolicy.java | 41 +++++------ .../java/io/bitsquare/btc/WalletService.java | 4 +- .../network/NetworkPreferencesViewCB.java | 11 ++- .../util/validation/BtcAddressValidator.java | 12 ++-- .../util/joptsimple/EnumValueConverter.java | 70 +++++++++++++++++++ 8 files changed, 132 insertions(+), 58 deletions(-) create mode 100644 src/main/java/io/bitsquare/util/joptsimple/EnumValueConverter.java diff --git a/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java b/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java index 67ef050693..e69680e0c8 100644 --- a/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java +++ b/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java @@ -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) diff --git a/src/main/java/io/bitsquare/btc/BitcoinModule.java b/src/main/java/io/bitsquare/btc/BitcoinModule.java index 2105829d3a..48eae71bfb 100644 --- a/src/main/java/io/bitsquare/btc/BitcoinModule.java +++ b/src/main/java/io/bitsquare/btc/BitcoinModule.java @@ -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); - } - } } diff --git a/src/main/java/io/bitsquare/btc/BitcoinNetwork.java b/src/main/java/io/bitsquare/btc/BitcoinNetwork.java index d0a1fa2007..152d01db6e 100644 --- a/src/main/java/io/bitsquare/btc/BitcoinNetwork.java +++ b/src/main/java/io/bitsquare/btc/BitcoinNetwork.java @@ -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; + } } diff --git a/src/main/java/io/bitsquare/btc/FeePolicy.java b/src/main/java/io/bitsquare/btc/FeePolicy.java index 1e3d2b92f1..183be85354 100644 --- a/src/main/java/io/bitsquare/btc/FeePolicy.java +++ b/src/main/java/io/bitsquare/btc/FeePolicy.java @@ -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; diff --git a/src/main/java/io/bitsquare/btc/WalletService.java b/src/main/java/io/bitsquare/btc/WalletService.java index 3a06f4c907..8f4b4aaa69 100644 --- a/src/main/java/io/bitsquare/btc/WalletService.java +++ b/src/main/java/io/bitsquare/btc/WalletService.java @@ -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; diff --git a/src/main/java/io/bitsquare/gui/main/preferences/network/NetworkPreferencesViewCB.java b/src/main/java/io/bitsquare/gui/main/preferences/network/NetworkPreferencesViewCB.java index f42808a023..e86dca40ca 100644 --- a/src/main/java/io/bitsquare/gui/main/preferences/network/NetworkPreferencesViewCB.java +++ b/src/main/java/io/bitsquare/gui/main/preferences/network/NetworkPreferencesViewCB.java @@ -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()); diff --git a/src/main/java/io/bitsquare/gui/util/validation/BtcAddressValidator.java b/src/main/java/io/bitsquare/gui/util/validation/BtcAddressValidator.java index 1a232a3e72..2fdd8b6481 100644 --- a/src/main/java/io/bitsquare/gui/util/validation/BtcAddressValidator.java +++ b/src/main/java/io/bitsquare/gui/util/validation/BtcAddressValidator.java @@ -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"); diff --git a/src/main/java/io/bitsquare/util/joptsimple/EnumValueConverter.java b/src/main/java/io/bitsquare/util/joptsimple/EnumValueConverter.java new file mode 100644 index 0000000000..f939eafa93 --- /dev/null +++ b/src/main/java/io/bitsquare/util/joptsimple/EnumValueConverter.java @@ -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 . + */ + +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 { + + private final Class enumType; + + public EnumValueConverter(Class 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 candidates = Sets.newHashSet(value, value.toUpperCase(), value.toLowerCase()); + for (String candidate : candidates) { + Optional 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 valueType() { + return enumType; + } + + @Override + public String valuePattern() { + return null; + } +}