mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 15:10:44 +01:00
Add spend infor to tx outputs. adopt json for txo. add custom encoding for bsq addresses.
This commit is contained in:
parent
2f865aa863
commit
30df6f9721
17 changed files with 514 additions and 154 deletions
|
@ -43,6 +43,8 @@ public class Version {
|
|||
public static final int TRADE_PROTOCOL_VERSION = 1;
|
||||
private static int p2pMessageVersion;
|
||||
|
||||
public static final String BSQ_TX_VERSION = "1";
|
||||
|
||||
public static int getP2PMessageVersion() {
|
||||
// TODO investigate why a changed NETWORK_PROTOCOL_VERSION for the serialized objects does not trigger
|
||||
// reliable a disconnect., but java serialisation should be replaced anyway, so using one existing field
|
||||
|
|
|
@ -21,18 +21,17 @@ import com.google.common.util.concurrent.FutureCallback;
|
|||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.inject.Inject;
|
||||
import com.neemre.btcdcli4j.core.domain.PubKeyScript;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.handlers.ErrorMessageHandler;
|
||||
import io.bisq.common.storage.FileManager;
|
||||
import io.bisq.common.storage.PlainTextWrapper;
|
||||
import io.bisq.common.storage.Storage;
|
||||
import io.bisq.common.util.MathUtils;
|
||||
import io.bisq.common.util.Utilities;
|
||||
import io.bisq.core.app.BisqEnvironment;
|
||||
import io.bisq.core.btc.BitcoinNetwork;
|
||||
import io.bisq.core.dao.RpcOptionKeys;
|
||||
import io.bisq.core.dao.blockchain.json.ScriptPubKeyJson;
|
||||
import io.bisq.core.dao.blockchain.json.SpentInfoJson;
|
||||
import io.bisq.core.dao.blockchain.json.ScriptPubKeyForJson;
|
||||
import io.bisq.core.dao.blockchain.json.SpentInfoForJson;
|
||||
import io.bisq.core.dao.blockchain.json.TxOutputForJson;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -41,10 +40,10 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import javax.inject.Named;
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BsqBlockchainManager {
|
||||
private static final Logger log = LoggerFactory.getLogger(BsqBlockchainManager.class);
|
||||
|
@ -86,6 +85,7 @@ public class BsqBlockchainManager {
|
|||
private int chainHeadHeight;
|
||||
@Getter
|
||||
private boolean isUtxoSyncWithChainHeadHeight;
|
||||
private final Storage<PlainTextWrapper> jsonStorage;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -96,9 +96,11 @@ public class BsqBlockchainManager {
|
|||
public BsqBlockchainManager(BsqBlockchainService blockchainService,
|
||||
BisqEnvironment bisqEnvironment,
|
||||
@Named(Storage.DIR_KEY) File storageDir,
|
||||
Storage<PlainTextWrapper> jsonStorage,
|
||||
@Named(RpcOptionKeys.DUMP_BLOCKCHAIN_DATA) boolean dumpBlockchainData) {
|
||||
this.blockchainService = blockchainService;
|
||||
this.storageDir = storageDir;
|
||||
this.jsonStorage = jsonStorage;
|
||||
this.dumpBlockchainData = dumpBlockchainData;
|
||||
this.bitcoinNetwork = bisqEnvironment.getBitcoinNetwork();
|
||||
|
||||
|
@ -110,7 +112,7 @@ public class BsqBlockchainManager {
|
|||
bsqTXOMap.addBurnedBSQTxMapListener(c -> onBsqTXOChanged());
|
||||
|
||||
if (dumpBlockchainData) {
|
||||
|
||||
this.jsonStorage.initWithFileName("txo.json");
|
||||
/* p2PService.addP2PServiceListener(new BootstrapListener() {
|
||||
@Override
|
||||
public void onBootstrapComplete() {
|
||||
|
@ -132,63 +134,67 @@ public class BsqBlockchainManager {
|
|||
}
|
||||
|
||||
private void doDumpBlockchainData() {
|
||||
bsqTXOMap.getMap().values().stream()
|
||||
.forEach(txOutput -> {
|
||||
final boolean coinBase = false;
|
||||
final int height = -1;
|
||||
final int index = txOutput.getIndex();
|
||||
final boolean invalid = false;
|
||||
final int n = index;
|
||||
final int output_index = index;
|
||||
List<TxOutputForJson> list = bsqTXOMap.getMap().values().stream()
|
||||
.map(this::getTxOutputForJson)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final ScriptPubKeyJson scriptPubKey = new ScriptPubKeyJson(txOutput.getAddresses(),
|
||||
"asm",
|
||||
"hex",
|
||||
-1,
|
||||
"type");
|
||||
final SpentInfoJson spent_info = new SpentInfoJson(-1, -1, "txId");
|
||||
list.sort((o1, o2) -> (o1.getSortData().compareTo(o2.getSortData())));
|
||||
TxOutputForJson[] array = new TxOutputForJson[list.size()];
|
||||
list.toArray(array);
|
||||
jsonStorage.queueUpForSave(new PlainTextWrapper(Utilities.objectToJson(array)), 5000);
|
||||
|
||||
final long squ_amount = txOutput.getValue();
|
||||
final String status = "?";
|
||||
final String transaction_version = "?";
|
||||
final long tx_time = -1;
|
||||
final String tx_type_str = "?";
|
||||
final String txid = txOutput.getTxId();
|
||||
final boolean validated = false;
|
||||
final double value = MathUtils.scaleDownByPowerOf10(squ_amount, 8);
|
||||
final long valueSat = squ_amount;
|
||||
// keep the individual file storage option as code as we dont know yet what we will use.
|
||||
/* log.error("txOutputForJson " + txOutputForJson);
|
||||
File txoDir = new File(Paths.get(storageDir.getAbsolutePath(), "txo").toString());
|
||||
if (!txoDir.exists())
|
||||
if (!txoDir.mkdir())
|
||||
log.warn("make txoDir failed.\ntxoDir=" + txoDir.getAbsolutePath());
|
||||
File txoFile = new File(Paths.get(txoDir.getAbsolutePath(),
|
||||
txOutput.getTxId() + ":" + outputIndex + ".json").toString());
|
||||
|
||||
// TODO WIP...
|
||||
TxOutputForJson txOutputForJson = new TxOutputForJson(coinBase,
|
||||
height,
|
||||
index,
|
||||
invalid,
|
||||
n,
|
||||
output_index,
|
||||
scriptPubKey,
|
||||
spent_info,
|
||||
squ_amount,
|
||||
status,
|
||||
transaction_version,
|
||||
tx_time,
|
||||
tx_type_str,
|
||||
txid,
|
||||
validated,
|
||||
value,
|
||||
valueSat
|
||||
);
|
||||
// log.error("txOutputForJson " + txOutputForJson);
|
||||
File txoDir = new File(Paths.get(storageDir.getAbsolutePath(), "txo").toString());
|
||||
if (!txoDir.exists())
|
||||
if (!txoDir.mkdir())
|
||||
log.warn("make txoDir failed.\ntxoDir=" + txoDir.getAbsolutePath());
|
||||
File txoFile = new File(Paths.get(txoDir.getAbsolutePath(), txid + ":" + index + ".json").toString());
|
||||
// Nr of write requests might be a bit heavy, consider write whole list to one file
|
||||
FileManager<PlainTextWrapper> fileManager = new FileManager<>(storageDir, txoFile, 1);
|
||||
fileManager.saveLater(new PlainTextWrapper(Utilities.objectToJson(txOutputForJson)));*/
|
||||
}
|
||||
|
||||
// Nr of write requests might be a bit heavy, consider write whole list to one file
|
||||
FileManager<PlainTextWrapper> fileManager = new FileManager<>(storageDir, txoFile, 1);
|
||||
fileManager.saveLater(new PlainTextWrapper(Utilities.objectToJson(txOutputForJson)));
|
||||
});
|
||||
private TxOutputForJson getTxOutputForJson(TxOutput txOutput) {
|
||||
String txId = txOutput.getTxId();
|
||||
int outputIndex = txOutput.getIndex();
|
||||
final long bsqAmount = txOutput.getValue();
|
||||
final int height = txOutput.getBlockHeight();
|
||||
final boolean isBsqCoinBase = txOutput.isBsqCoinBase();
|
||||
final boolean verified = txOutput.isVerified();
|
||||
final long burnedFee = txOutput.getBurnedFee();
|
||||
final long btcTxFee = txOutput.getBtcTxFee();
|
||||
|
||||
PubKeyScript pubKeyScript = txOutput.getPubKeyScript();
|
||||
final ScriptPubKeyForJson scriptPubKey = new ScriptPubKeyForJson(pubKeyScript.getAddresses(),
|
||||
pubKeyScript.getAsm(),
|
||||
pubKeyScript.getHex(),
|
||||
pubKeyScript.getReqSigs(),
|
||||
pubKeyScript.getType().toString());
|
||||
SpentInfoForJson spentInfoJson = null;
|
||||
SpendInfo spendInfo = txOutput.getSpendInfo();
|
||||
if (spendInfo != null)
|
||||
spentInfoJson = new SpentInfoForJson(spendInfo.getBlockHeight(),
|
||||
spendInfo.getInputIndex(),
|
||||
spendInfo.getTxId());
|
||||
|
||||
final long time = txOutput.getTime();
|
||||
final String txVersion = txOutput.getTxVersion();
|
||||
return new TxOutputForJson(txId,
|
||||
outputIndex,
|
||||
bsqAmount,
|
||||
height,
|
||||
isBsqCoinBase,
|
||||
verified,
|
||||
burnedFee,
|
||||
btcTxFee,
|
||||
scriptPubKey,
|
||||
spentInfoJson,
|
||||
time,
|
||||
txVersion
|
||||
);
|
||||
}
|
||||
|
||||
private void onBsqUTXOChanged() {
|
||||
|
|
|
@ -37,7 +37,6 @@ import io.bisq.core.dao.RpcOptionKeys;
|
|||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -51,7 +50,6 @@ import java.util.function.Consumer;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.bitcoinj.core.Utils.HEX;
|
||||
|
||||
public class BsqBlockchainRpcService extends BsqBlockchainService {
|
||||
private static final Logger log = LoggerFactory.getLogger(BsqBlockchainRpcService.class);
|
||||
|
@ -198,35 +196,27 @@ public class BsqBlockchainRpcService extends BsqBlockchainService {
|
|||
}
|
||||
|
||||
@Override
|
||||
Tx requestTransaction(String txId) throws BsqBlockchainException {
|
||||
Tx requestTransaction(String txId, int blockHeight) throws BsqBlockchainException {
|
||||
try {
|
||||
RawTransaction rawTransaction = getRawTransaction(txId);
|
||||
final long time = rawTransaction.getTime() * 1000;
|
||||
final List<TxInput> txInputs = rawTransaction.getVIn()
|
||||
.stream()
|
||||
.filter(rawInput -> rawInput != null && rawInput.getVOut() != null && rawInput.getTxId() != null)
|
||||
.map(rawInput -> new TxInput(rawInput.getVOut(), rawInput.getTxId(), rawTransaction.getHex()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<TxOutput> txOutputs = rawTransaction.getVOut()
|
||||
.stream()
|
||||
.filter(e -> e != null && e.getN() != null && e.getValue() != null && e.getScriptPubKey() != null)
|
||||
.map(e -> {
|
||||
byte[] scriptProgramBytes = new byte[]{};
|
||||
try {
|
||||
scriptProgramBytes = e.getScriptPubKey().getHex() != null ?
|
||||
new Script(HEX.decode(e.getScriptPubKey().getHex())).getProgram() : new byte[]{};
|
||||
} catch (Throwable t) {
|
||||
// expected for tx: 0f8e9655b29d76c5e01147704a64faf95a9c90433baacdd39d4c1d2667e570a2
|
||||
log.error(e.getScriptPubKey().getAsm());
|
||||
log.error(e.getScriptPubKey().getHex());
|
||||
log.error(e.getScriptPubKey().toString());
|
||||
log.error(t.toString());
|
||||
t.printStackTrace();
|
||||
}
|
||||
return new TxOutput(e.getN(),
|
||||
e.getValue().movePointRight(8).longValue(),
|
||||
e.getScriptPubKey().getAddresses(),
|
||||
.map(rawOutput -> {
|
||||
|
||||
return new TxOutput(rawOutput.getN(),
|
||||
rawOutput.getValue().movePointRight(8).longValue(),
|
||||
rawTransaction.getTxId(),
|
||||
scriptProgramBytes);
|
||||
rawOutput.getScriptPubKey(),
|
||||
blockHeight,
|
||||
time);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
@ -234,7 +224,7 @@ public class BsqBlockchainRpcService extends BsqBlockchainService {
|
|||
return new Tx(txId,
|
||||
txInputs,
|
||||
txOutputs,
|
||||
rawTransaction.getTime() * 1000);
|
||||
time);
|
||||
} catch (BitcoindException | CommunicationException e) {
|
||||
throw new BsqBlockchainException(e.getMessage(), e);
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ abstract public class BsqBlockchainService {
|
|||
|
||||
abstract Block requestBlock(int i) throws BitcoindException, CommunicationException;
|
||||
|
||||
abstract Tx requestTransaction(String txId) throws BsqBlockchainException;
|
||||
abstract Tx requestTransaction(String txId, int blockHeight) throws BsqBlockchainException;
|
||||
|
||||
@VisibleForTesting
|
||||
void parseBlockchain(BsqUTXOMap bsqUTXOMap,
|
||||
|
@ -138,7 +138,7 @@ abstract public class BsqBlockchainService {
|
|||
List<String> txIds = block.getTxIds();
|
||||
Tx genesisTx = null;
|
||||
for (String txId : txIds) {
|
||||
final Tx tx = requestTransaction(txId);
|
||||
final Tx tx = requestTransaction(txId, blockHeight);
|
||||
block.addTx(tx);
|
||||
if (txId.equals(genesisTxId))
|
||||
genesisTx = tx;
|
||||
|
@ -270,12 +270,19 @@ abstract public class BsqBlockchainService {
|
|||
long availableValue = 0;
|
||||
long totalAvailableBSQInputs = 0;
|
||||
long totalSpendBSQOutputs = 0;
|
||||
for (TxInput input : tx.getInputs()) {
|
||||
final String txId = tx.getId();
|
||||
for (int inputIndex = 0; inputIndex < tx.getInputs().size(); inputIndex++) {
|
||||
TxInput input = tx.getInputs().get(inputIndex);
|
||||
String spendingTxId = input.getSpendingTxId();
|
||||
final int spendingTxOutputIndex = input.getSpendingTxOutputIndex();
|
||||
|
||||
if (bsqTXOMap.containsTuple(spendingTxId, spendingTxOutputIndex)) {
|
||||
TxOutput txOutputFromSpendingTx = bsqTXOMap.getByTuple(spendingTxId, spendingTxOutputIndex);
|
||||
txOutputFromSpendingTx.setSpendInfo(new SpendInfo(blockHeight, txId, inputIndex));
|
||||
}
|
||||
|
||||
if (bsqUTXOMap.containsTuple(spendingTxId, spendingTxOutputIndex)) {
|
||||
BsqUTXO bsqUTXO = bsqUTXOMap.getByTuple(spendingTxId, spendingTxOutputIndex);
|
||||
log.debug("input value " + bsqUTXO.getValue());
|
||||
availableValue = availableValue + bsqUTXO.getValue();
|
||||
totalAvailableBSQInputs += bsqUTXO.getValue();
|
||||
bsqUTXOMap.removeByTuple(spendingTxId, spendingTxOutputIndex);
|
||||
|
@ -292,14 +299,8 @@ abstract public class BsqBlockchainService {
|
|||
for (TxOutput txOutput : outputs) {
|
||||
availableValue = availableValue - txOutput.getValue();
|
||||
if (availableValue >= 0) {
|
||||
if (txOutput.getAddresses().size() != 1) {
|
||||
final String msg = "We got a address list with more or less than 1 address for a BsqUTXO. " +
|
||||
"Seems to be a raw MS. Raw MS are not supported with BSQ.\n" + this.toString();
|
||||
log.warn(msg);
|
||||
if (DevEnv.DEV_MODE)
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
// We are spending available tokens
|
||||
txOutput.setVerified(true);
|
||||
bsqUTXOMap.add(new BsqUTXO(blockHeight, txOutput, false));
|
||||
bsqTXOMap.add(txOutput);
|
||||
totalSpendBSQOutputs += txOutput.getValue();
|
||||
|
@ -315,11 +316,12 @@ abstract public class BsqBlockchainService {
|
|||
}
|
||||
}
|
||||
|
||||
if (totalAvailableBSQInputs - totalSpendBSQOutputs > 0) {
|
||||
final long burnedAmount = totalAvailableBSQInputs - totalSpendBSQOutputs;
|
||||
if (burnedAmount > 0) {
|
||||
log.debug("BSQ have been left which was not spent. Burned BSQ amount={}, tx={}",
|
||||
availableValue,
|
||||
tx.toString());
|
||||
|
||||
tx.getOutputs().stream().forEach(e -> e.setBurnedFee(burnedAmount));
|
||||
bsqTXOMap.addBurnedBSQTx(tx);
|
||||
}
|
||||
|
||||
|
@ -336,13 +338,8 @@ abstract public class BsqBlockchainService {
|
|||
//TODO use BsqTXO not BsqUTXO as we dont know if they are unspent
|
||||
// Genesis tx uses all outputs as BSQ outputs
|
||||
for (TxOutput txOutput : outputs) {
|
||||
if (txOutput.getAddresses().size() != 1) {
|
||||
final String msg = "We got a address list with more or less than 1 address. " +
|
||||
"Seems to be a raw MS. Raw MS are not supported with BSQ.\n" + this.toString();
|
||||
log.warn(msg);
|
||||
if (DevEnv.DEV_MODE)
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
txOutput.setVerified(true);
|
||||
txOutput.setBsqCoinBase(true);
|
||||
bsqUTXOMap.add(new BsqUTXO(blockHeight, txOutput, true));
|
||||
bsqTXOMap.add(txOutput);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import lombok.Value;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
// Estimation for UTXO set: 1 UTXO object has 78 byte
|
||||
// 1000 UTXOs - 10 000 UTXOs: 78kb -780kb
|
||||
|
@ -43,10 +42,7 @@ public class BsqUTXO implements Serializable {
|
|||
}
|
||||
|
||||
public String getAddress() {
|
||||
// Only at raw MS outputs addresses have more then 1 entry
|
||||
// We do not support raw MS for BSQ but lets see if is needed anyway, might be removed
|
||||
final List<String> addresses = txOutput.getAddresses();
|
||||
return addresses.size() == 1 ? addresses.get(0) : addresses.toString();
|
||||
return txOutput.getAddress();
|
||||
}
|
||||
|
||||
public long getValue() {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.bisq.core.dao.blockchain;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
public class SpendInfo {
|
||||
private final long blockHeight;
|
||||
private final String txId;
|
||||
private final int inputIndex;
|
||||
}
|
|
@ -17,28 +17,103 @@
|
|||
|
||||
package io.bisq.core.dao.blockchain;
|
||||
|
||||
import lombok.Value;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import com.neemre.btcdcli4j.core.domain.PubKeyScript;
|
||||
import io.bisq.common.app.DevEnv;
|
||||
import io.bisq.common.app.Version;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Value
|
||||
@Getter
|
||||
@EqualsAndHashCode
|
||||
@Slf4j
|
||||
public class TxOutput implements Serializable {
|
||||
// Immutable
|
||||
private final int index;
|
||||
private final long value;
|
||||
private final List<String> addresses;
|
||||
private final String txId;
|
||||
private final byte[] scriptProgramBytes;
|
||||
private final PubKeyScript pubKeyScript;
|
||||
private final int blockHeight;
|
||||
private final long time;
|
||||
private final String txVersion = Version.BSQ_TX_VERSION;
|
||||
|
||||
// Mutable
|
||||
@Setter
|
||||
private boolean isBsqCoinBase;
|
||||
@Setter
|
||||
private boolean isVerified;
|
||||
@Setter
|
||||
private long burnedFee;
|
||||
|
||||
@Nullable
|
||||
@Setter
|
||||
private long btcTxFee;
|
||||
|
||||
@Nullable
|
||||
@Setter
|
||||
private SpendInfo spendInfo;
|
||||
|
||||
// Lazy set
|
||||
@Nullable
|
||||
private String address;
|
||||
|
||||
|
||||
public TxOutput(int index,
|
||||
long value,
|
||||
String txId,
|
||||
PubKeyScript pubKeyScript,
|
||||
int blockHeight,
|
||||
long time) {
|
||||
this.index = index;
|
||||
this.value = value;
|
||||
this.txId = txId;
|
||||
this.pubKeyScript = pubKeyScript;
|
||||
this.blockHeight = blockHeight;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public List<String> getAddresses() {
|
||||
return pubKeyScript.getAddresses();
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
if (address == null) {
|
||||
// Only at raw MS outputs addresses have more then 1 entry
|
||||
// We do not support raw MS for BSQ but lets see if is needed anyway, might be removed
|
||||
final List<String> addresses = pubKeyScript.getAddresses();
|
||||
if (addresses.size() == 1) {
|
||||
address = addresses.get(0);
|
||||
} else if (addresses.size() > 1) {
|
||||
final String msg = "We got a raw Multisig script. That is not supported for BSQ tokens.";
|
||||
log.warn(msg);
|
||||
address = addresses.toString();
|
||||
if (DevEnv.DEV_MODE)
|
||||
throw new RuntimeException(msg);
|
||||
} else if (addresses.isEmpty()) {
|
||||
final String msg = "We got no address. Unsupported pubKeyScript";
|
||||
log.warn(msg);
|
||||
address = "";
|
||||
if (DevEnv.DEV_MODE)
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TxOutput{" +
|
||||
"\n index=" + index +
|
||||
",\n value=" + value +
|
||||
",\n addresses=" + addresses +
|
||||
",\n address=" + getAddress() +
|
||||
",\n txId=" + txId +
|
||||
",\n scriptProgramBytes=" + Hex.toHexString(scriptProgramBytes) +
|
||||
",\n pubKeyScript=" + pubKeyScript +
|
||||
",\n spendInfo=" + spendInfo +
|
||||
"\n" +
|
||||
" }";
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import lombok.Value;
|
|||
import java.util.List;
|
||||
|
||||
@Value
|
||||
public class ScriptPubKeyJson {
|
||||
public class ScriptPubKeyForJson {
|
||||
private final List<String> addresses;
|
||||
private final String asm;
|
||||
private final String hex;
|
|
@ -20,8 +20,8 @@ package io.bisq.core.dao.blockchain.json;
|
|||
import lombok.Value;
|
||||
|
||||
@Value
|
||||
public class SpentInfoJson {
|
||||
public class SpentInfoForJson {
|
||||
private final long height;
|
||||
private final int index;
|
||||
private final String txid;
|
||||
}
|
||||
private final int inputIndex;
|
||||
private final String txId;
|
||||
}
|
|
@ -21,23 +21,21 @@ import lombok.Value;
|
|||
|
||||
@Value
|
||||
public class TxOutputForJson {
|
||||
private final boolean coinBase;
|
||||
private final String txId;
|
||||
private final int outputIndex;
|
||||
private final long bsqAmount;
|
||||
private final int height;
|
||||
private final int index;
|
||||
private final boolean invalid;
|
||||
private final int n;
|
||||
private final int output_index;
|
||||
private final boolean isBsqCoinBase;
|
||||
private final boolean isVerified;
|
||||
private final long burnedFee;
|
||||
private final long btcTxFee;
|
||||
private final ScriptPubKeyForJson scriptPubKey;
|
||||
private final SpentInfoForJson spentInfo;
|
||||
private final long time;
|
||||
private final String txVersion;
|
||||
|
||||
private final ScriptPubKeyJson scriptPubKey;
|
||||
private final SpentInfoJson spent_info;
|
||||
public String getSortData() {
|
||||
return height + txId + outputIndex;
|
||||
}
|
||||
|
||||
private final long squ_amount;
|
||||
private final String status;
|
||||
private final String transaction_version;
|
||||
private final long tx_time;
|
||||
private final String tx_type_str;
|
||||
private final String txid;
|
||||
private final boolean validated;
|
||||
private final double value;
|
||||
private final long valueSat;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import javafx.scene.image.ImageView;
|
|||
import javafx.scene.layout.GridPane;
|
||||
import net.glxn.qrgen.QRCode;
|
||||
import net.glxn.qrgen.image.ImageType;
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.uri.BitcoinURI;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
@ -58,7 +59,7 @@ public class BsqReceiveView extends ActivatableView<GridPane, Void> {
|
|||
private TextField balanceTextField;
|
||||
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final BsqFormatter formatter;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final BalanceUtil balanceUtil;
|
||||
|
||||
private int gridRow = 0;
|
||||
|
@ -71,9 +72,9 @@ public class BsqReceiveView extends ActivatableView<GridPane, Void> {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
private BsqReceiveView(BsqWalletService bsqWalletService, BsqFormatter formatter, BalanceUtil balanceUtil) {
|
||||
private BsqReceiveView(BsqWalletService bsqWalletService, BsqFormatter bsqFormatter, BalanceUtil balanceUtil) {
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.formatter = formatter;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
this.balanceUtil = balanceUtil;
|
||||
paymentLabelString = Res.get("dao.wallet.receive.fundBSQWallet");
|
||||
}
|
||||
|
@ -108,7 +109,7 @@ public class BsqReceiveView extends ActivatableView<GridPane, Void> {
|
|||
balanceUtil.activate();
|
||||
|
||||
amountTextFieldSubscription = EasyBind.subscribe(amountTextField.textProperty(), t -> {
|
||||
addressTextField.setAmountAsCoin(formatter.parseToCoin(t));
|
||||
addressTextField.setAmountAsCoin(bsqFormatter.parseToCoin(t));
|
||||
updateQRCode();
|
||||
});
|
||||
qrCodeImageView.setOnMouseClicked(e -> GUIUtil.showFeeInfoBeforeExecute(
|
||||
|
@ -116,7 +117,7 @@ public class BsqReceiveView extends ActivatableView<GridPane, Void> {
|
|||
() -> new QRCodeWindow(getBitcoinURI()).show(),
|
||||
200, TimeUnit.MILLISECONDS)
|
||||
));
|
||||
addressTextField.setAddress(bsqWalletService.freshReceiveAddress().toString());
|
||||
addressTextField.setAddress(bsqFormatter.getBsqAddressStringFromAddress(bsqWalletService.freshReceiveAddress()));
|
||||
updateQRCode();
|
||||
}
|
||||
|
||||
|
@ -142,11 +143,12 @@ public class BsqReceiveView extends ActivatableView<GridPane, Void> {
|
|||
}
|
||||
|
||||
private Coin getAmountAsCoin() {
|
||||
return formatter.parseToCoin(amountTextField.getText());
|
||||
return bsqFormatter.parseToCoin(amountTextField.getText());
|
||||
}
|
||||
|
||||
private String getBitcoinURI() {
|
||||
return BitcoinURI.convertToBitcoinURI(addressTextField.getAddress(),
|
||||
Address addressFromBsqAddress = bsqFormatter.getAddressFromBsqAddress(addressTextField.getAddress());
|
||||
return BitcoinURI.convertToBitcoinURI(addressFromBsqAddress,
|
||||
getAmountAsCoin(),
|
||||
paymentLabelString,
|
||||
null);
|
||||
|
|
|
@ -53,7 +53,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> {
|
|||
|
||||
private final BsqWalletService bsqWalletService;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final BSFormatter bsqFormatter;
|
||||
private final BsqFormatter bsqFormatter;
|
||||
private final BSFormatter btcFormatter;
|
||||
private final BalanceUtil balanceUtil;
|
||||
private BsqValidator bsqValidator;
|
||||
|
@ -113,7 +113,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> {
|
|||
}
|
||||
|
||||
sendButton.setOnAction((event) -> {
|
||||
String receiversAddressString = receiversAddressInputTextField.getText();
|
||||
String receiversAddressString = bsqFormatter.getAddressFromBsqAddress(receiversAddressInputTextField.getText()).toString();
|
||||
Coin receiverAmount = bsqFormatter.parseToCoin(amountInputTextField.getText());
|
||||
try {
|
||||
Transaction preparedSendTx = bsqWalletService.getPreparedSendTx(receiversAddressString, receiverAmount);
|
||||
|
@ -124,7 +124,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> {
|
|||
new Popup().headLine(Res.get("dao.wallet.send.sendFunds.headline"))
|
||||
.confirmation(Res.get("dao.wallet.send.sendFunds.details",
|
||||
bsqFormatter.formatCoinWithCode(receiverAmount),
|
||||
receiversAddressString,
|
||||
receiversAddressInputTextField.getText(),
|
||||
btcFormatter.formatCoinWithCode(miningFee),
|
||||
CoinUtil.getFeePerByte(miningFee, txSize),
|
||||
txSize / 1000d,
|
||||
|
|
|
@ -23,6 +23,7 @@ import io.bisq.core.btc.wallet.BsqWalletService;
|
|||
import io.bisq.core.btc.wallet.BtcWalletService;
|
||||
import io.bisq.core.btc.wallet.WalletUtils;
|
||||
import io.bisq.gui.components.indicator.TxConfidenceIndicator;
|
||||
import io.bisq.gui.util.BsqFormatter;
|
||||
import io.bisq.gui.util.GUIUtil;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import lombok.Getter;
|
||||
|
@ -61,6 +62,7 @@ class BsqTxListItem {
|
|||
private boolean received;
|
||||
@Getter
|
||||
private boolean isBurnedBsqTx;
|
||||
private BsqFormatter bsqFormatter;
|
||||
@Getter
|
||||
private TxConfidenceIndicator txConfidenceIndicator;
|
||||
|
||||
|
@ -69,11 +71,13 @@ class BsqTxListItem {
|
|||
public BsqTxListItem(Transaction transaction,
|
||||
BsqWalletService bsqWalletService,
|
||||
BtcWalletService btcWalletService,
|
||||
boolean isBurnedBsqTx) {
|
||||
boolean isBurnedBsqTx,
|
||||
BsqFormatter bsqFormatter) {
|
||||
this.transaction = transaction;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.isBurnedBsqTx = isBurnedBsqTx;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
|
||||
txId = transaction.getHashAsString();
|
||||
date = transaction.getUpdateTime();
|
||||
|
@ -106,7 +110,7 @@ class BsqTxListItem {
|
|||
WalletUtils.isOutputScriptConvertableToAddress(output)) {
|
||||
// We don't support send txs with multiple outputs to multiple receivers, so we can
|
||||
// assume that only one output is not from our own wallets.
|
||||
foreignReceiverAddress = WalletUtils.getAddressStringFromOutput(output);
|
||||
foreignReceiverAddress = bsqFormatter.getBsqAddressStringFromAddress(WalletUtils.getAddressFromOutput(output));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +121,7 @@ class BsqTxListItem {
|
|||
if (foreignReceiverAddress != null) {
|
||||
for (TransactionOutput output : transaction.getOutputs()) {
|
||||
if (WalletUtils.isOutputScriptConvertableToAddress(output)) {
|
||||
ownReceiverAddress = WalletUtils.getAddressStringFromOutput(output);
|
||||
ownReceiverAddress = bsqFormatter.getBsqAddressStringFromAddress(WalletUtils.getAddressFromOutput(output));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,9 +134,10 @@ public class BsqTxView extends ActivatableView<GridPane, Void> {
|
|||
Map<String, Tx> burnedBSQTxIdMap = bsqBlockchainManager.getBsqTXOMap().getBurnedBSQTxMap();
|
||||
Set<BsqTxListItem> list = bsqWalletService.getWalletBsqTransactions().stream()
|
||||
.map(transaction -> new BsqTxListItem(transaction,
|
||||
bsqWalletService,
|
||||
btcWalletService,
|
||||
burnedBSQTxIdMap.containsKey(transaction.getHashAsString())))
|
||||
bsqWalletService,
|
||||
btcWalletService,
|
||||
burnedBSQTxIdMap.containsKey(transaction.getHashAsString()), bsqFormatter)
|
||||
)
|
||||
.collect(Collectors.toSet());
|
||||
observableList.setAll(list);
|
||||
|
||||
|
|
211
gui/src/main/java/io/bisq/gui/util/Base58Bsq.java
Normal file
211
gui/src/main/java/io/bisq/gui/util/Base58Bsq.java
Normal file
|
@ -0,0 +1,211 @@
|
|||
/**
|
||||
* Copyright 2011 Google Inc.
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.bisq.gui.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bitcoinj.core.AddressFormatException;
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
import org.bitcoinj.core.Utils;
|
||||
import org.bitcoinj.core.VersionedChecksummedBytes;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* <p>Base58 is a way to encode Bitcoin addresses as numbers and letters. Note that this is not the same base58 as used by
|
||||
* Flickr, which you may see reference to around the internet.</p>
|
||||
*
|
||||
* <p>You may instead wish to work with {@link VersionedChecksummedBytes}, which adds support for testing the prefix
|
||||
* and suffix bytes commonly found in addresses.</p>
|
||||
*
|
||||
* <p>Satoshi says: why base-58 instead of standard base-64 encoding?<p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>Don't want 0OIl characters that look the same in some fonts and
|
||||
* could be used to create visually identical looking account numbers.</li>
|
||||
* <li>A string with non-alphanumeric characters is not as easily accepted as an account number.</li>
|
||||
* <li>E-mail usually won't line-break if there's no punctuation to break at.</li>
|
||||
* <li>Doubleclicking selects the whole number as one word if it's all alphanumeric.</li>
|
||||
* </ul>
|
||||
*/
|
||||
|
||||
// We use Base58 with a different alphabet order, so we would get a checksum failure if the user mixes up btc and bsq
|
||||
@Slf4j
|
||||
public class Base58Bsq {
|
||||
// public static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
|
||||
// we wan tot have B at beginning, usually its 1 for btc addresses
|
||||
public static final char[] ALPHABET = "BCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789A".toCharArray();
|
||||
|
||||
private static final int[] INDEXES = new int[128];
|
||||
|
||||
static {
|
||||
for (int i = 0; i < INDEXES.length; i++) {
|
||||
INDEXES[i] = -1;
|
||||
}
|
||||
for (int i = 0; i < ALPHABET.length; i++) {
|
||||
INDEXES[ALPHABET[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
/** Encodes the given bytes in base58. No checksum is appended. */
|
||||
public static String encode(byte[] input) {
|
||||
if (input.length == 0) {
|
||||
return "";
|
||||
}
|
||||
input = copyOfRange(input, 0, input.length);
|
||||
// Count leading zeroes.
|
||||
int zeroCount = 0;
|
||||
while (zeroCount < input.length && input[zeroCount] == 0) {
|
||||
++zeroCount;
|
||||
}
|
||||
// The actual encoding.
|
||||
byte[] temp = new byte[input.length * 2];
|
||||
int j = temp.length;
|
||||
|
||||
int startAt = zeroCount;
|
||||
while (startAt < input.length) {
|
||||
byte mod = divmod58(input, startAt);
|
||||
if (input[startAt] == 0) {
|
||||
++startAt;
|
||||
}
|
||||
temp[--j] = (byte) ALPHABET[mod];
|
||||
}
|
||||
|
||||
// Strip extra '1' if there are some after decoding.
|
||||
while (j < temp.length && temp[j] == ALPHABET[0]) {
|
||||
++j;
|
||||
}
|
||||
// Add as many leading '1' as there were leading zeros.
|
||||
while (--zeroCount >= 0) {
|
||||
temp[--j] = (byte) ALPHABET[0];
|
||||
}
|
||||
|
||||
byte[] output = copyOfRange(temp, j, temp.length);
|
||||
return Utils.toString(output, "US-ASCII");
|
||||
}
|
||||
|
||||
public static byte[] decode(String input) throws AddressFormatException {
|
||||
if (input.length() == 0) {
|
||||
return new byte[0];
|
||||
}
|
||||
byte[] input58 = new byte[input.length()];
|
||||
// Transform the String to a base58 byte sequence
|
||||
for (int i = 0; i < input.length(); ++i) {
|
||||
char c = input.charAt(i);
|
||||
|
||||
int digit58 = -1;
|
||||
if (c >= 0 && c < 128) {
|
||||
digit58 = INDEXES[c];
|
||||
}
|
||||
if (digit58 < 0) {
|
||||
throw new AddressFormatException("Illegal character " + c + " at " + i);
|
||||
}
|
||||
|
||||
input58[i] = (byte) digit58;
|
||||
}
|
||||
// Count leading zeroes
|
||||
int zeroCount = 0;
|
||||
while (zeroCount < input58.length && input58[zeroCount] == 0) {
|
||||
++zeroCount;
|
||||
}
|
||||
// The encoding
|
||||
byte[] temp = new byte[input.length()];
|
||||
int j = temp.length;
|
||||
|
||||
int startAt = zeroCount;
|
||||
while (startAt < input58.length) {
|
||||
byte mod = divmod256(input58, startAt);
|
||||
if (input58[startAt] == 0) {
|
||||
++startAt;
|
||||
}
|
||||
|
||||
temp[--j] = mod;
|
||||
}
|
||||
// Do no add extra leading zeroes, move j to first non null byte.
|
||||
while (j < temp.length && temp[j] == 0) {
|
||||
++j;
|
||||
}
|
||||
|
||||
return copyOfRange(temp, j - zeroCount, temp.length);
|
||||
}
|
||||
|
||||
public static BigInteger decodeToBigInteger(String input) throws AddressFormatException {
|
||||
return new BigInteger(1, decode(input));
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the checksum in the last 4 bytes of the decoded data to verify the rest are correct. The checksum is
|
||||
* removed from the returned data.
|
||||
*
|
||||
* @throws AddressFormatException if the input is not base 58 or the checksum does not validate.
|
||||
*/
|
||||
public static byte[] decodeChecked(String input) throws AddressFormatException {
|
||||
byte[] tmp = decode(input);
|
||||
if (tmp.length < 4)
|
||||
throw new AddressFormatException("Input too short");
|
||||
byte[] bytes = copyOfRange(tmp, 0, tmp.length - 4);
|
||||
byte[] checksum = copyOfRange(tmp, tmp.length - 4, tmp.length);
|
||||
|
||||
tmp = Sha256Hash.hashTwice(bytes);
|
||||
byte[] hash = copyOfRange(tmp, 0, 4);
|
||||
if (!Arrays.equals(checksum, hash))
|
||||
throw new AddressFormatException("Checksum does not validate");
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
//
|
||||
// number -> number / 58, returns number % 58
|
||||
//
|
||||
private static byte divmod58(byte[] number, int startAt) {
|
||||
int remainder = 0;
|
||||
for (int i = startAt; i < number.length; i++) {
|
||||
int digit256 = (int) number[i] & 0xFF;
|
||||
int temp = remainder * 256 + digit256;
|
||||
|
||||
number[i] = (byte) (temp / 58);
|
||||
|
||||
remainder = temp % 58;
|
||||
}
|
||||
|
||||
return (byte) remainder;
|
||||
}
|
||||
|
||||
//
|
||||
// number -> number / 256, returns number % 256
|
||||
//
|
||||
private static byte divmod256(byte[] number58, int startAt) {
|
||||
int remainder = 0;
|
||||
for (int i = startAt; i < number58.length; i++) {
|
||||
int digit58 = (int) number58[i] & 0xFF;
|
||||
int temp = remainder * 58 + digit58;
|
||||
|
||||
number58[i] = (byte) (temp / 256);
|
||||
|
||||
remainder = temp % 256;
|
||||
}
|
||||
|
||||
return (byte) remainder;
|
||||
}
|
||||
|
||||
private static byte[] copyOfRange(byte[] source, int from, int to) {
|
||||
byte[] range = new byte[to - from];
|
||||
System.arraycopy(source, from, range, 0, range.length);
|
||||
|
||||
return range;
|
||||
}
|
||||
}
|
|
@ -17,6 +17,10 @@
|
|||
|
||||
package io.bisq.gui.util;
|
||||
|
||||
import io.bisq.core.btc.wallet.WalletUtils;
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.AddressFormatException;
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -25,6 +29,7 @@ import javax.inject.Inject;
|
|||
|
||||
public class BsqFormatter extends BSFormatter {
|
||||
private static final Logger log = LoggerFactory.getLogger(BsqFormatter.class);
|
||||
private static final boolean useBsqAddressFormat = false;
|
||||
|
||||
@Inject
|
||||
private BsqFormatter() {
|
||||
|
@ -32,4 +37,50 @@ public class BsqFormatter extends BSFormatter {
|
|||
coinFormat = new MonetaryFormat().shift(5).code(5, "BSQ").minDecimals(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base-58 encoded String representation of this
|
||||
* object, including version and checksum bytes.
|
||||
*/
|
||||
public String getBsqAddressStringFromAddress(Address address) {
|
||||
if (useBsqAddressFormat) {
|
||||
byte[] bytes = address.getHash160();
|
||||
int version = address.getVersion();
|
||||
// A stringified buffer is:
|
||||
// 1 byte version + data bytes + 4 bytes check code (a truncated hash)
|
||||
byte[] addressBytes = new byte[1 + bytes.length + 4];
|
||||
addressBytes[0] = (byte) version;
|
||||
System.arraycopy(bytes, 0, addressBytes, 1, bytes.length);
|
||||
byte[] checksum = Sha256Hash.hashTwice(addressBytes, 0, bytes.length + 1);
|
||||
System.arraycopy(checksum, 0, addressBytes, bytes.length + 1, 4);
|
||||
// return "BSQ" + Base58Bsq.encode(addressBytes);
|
||||
return Base58Bsq.encode(addressBytes);
|
||||
} else {
|
||||
return address.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Address getAddressFromBsqAddress(String encoded) {
|
||||
if (useBsqAddressFormat) {
|
||||
try {
|
||||
//encoded = encoded.substring(3, encoded.length());
|
||||
byte[] versionAndDataBytes = Base58Bsq.decodeChecked(encoded);
|
||||
byte[] bytes = new byte[versionAndDataBytes.length - 1];
|
||||
System.arraycopy(versionAndDataBytes, 1, bytes, 0, versionAndDataBytes.length - 1);
|
||||
return new Address(WalletUtils.getParameters(), bytes);
|
||||
} catch (AddressFormatException e) {
|
||||
log.error(e.toString());
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return new Address(WalletUtils.getParameters(), encoded);
|
||||
} catch (AddressFormatException e) {
|
||||
log.error(e.toString());
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,20 +18,20 @@
|
|||
package io.bisq.gui.util.validation;
|
||||
|
||||
import io.bisq.common.locale.Res;
|
||||
import io.bisq.core.btc.wallet.WalletUtils;
|
||||
import io.bisq.core.user.Preferences;
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.AddressFormatException;
|
||||
import io.bisq.gui.util.BsqFormatter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public final class BsqAddressValidator extends InputValidator {
|
||||
|
||||
private final Preferences preferences;
|
||||
private BsqFormatter bsqFormatter;
|
||||
|
||||
@Inject
|
||||
public BsqAddressValidator(Preferences preferences) {
|
||||
public BsqAddressValidator(Preferences preferences, BsqFormatter bsqFormatter) {
|
||||
this.preferences = preferences;
|
||||
this.bsqFormatter = bsqFormatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,9 +46,9 @@ public final class BsqAddressValidator extends InputValidator {
|
|||
|
||||
private ValidationResult validateBsqAddress(String input) {
|
||||
try {
|
||||
new Address(WalletUtils.getParameters(), input);
|
||||
bsqFormatter.getAddressFromBsqAddress(input);
|
||||
return new ValidationResult(true);
|
||||
} catch (AddressFormatException e) {
|
||||
} catch (Throwable e) {
|
||||
return new ValidationResult(false, Res.get("validation.bsq.invalidFormat"));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue