Store difficulty as floating point in Filter & PoW

Change the type of the 'difficulty' field in the Filter & ProofOfWork
proto objects from int32/bytes to double and make it use a linear scale,
in place of the original logarithmic scale which counts the (effective)
number of required zeros.

This allows fine-grained difficulty control for Equihash, though for
Hashcash it simply rounds up to the nearest power of 2 internally.

NOTE: This is a breaking change to PoW & filter serialisation (unlike
the earlier PR commits), as the proto field version nums aren't updated.
This commit is contained in:
Steven Barclay 2021-11-26 04:06:24 +00:00
parent 0c94e232f8
commit e0595aa284
No known key found for this signature in database
GPG Key ID: 9FED6BF1176D500B
10 changed files with 77 additions and 91 deletions

View File

@ -31,7 +31,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
@Slf4j @Slf4j
public class EquihashProofOfWorkService extends ProofOfWorkService { public class EquihashProofOfWorkService extends ProofOfWorkService {
/** Rough cost of one Hashcash iteration compared to solving an Equihash-90-5 puzzle of unit difficulty. */ /** Rough cost of two Hashcash iterations compared to solving an Equihash-90-5 puzzle of unit difficulty. */
private static final double DIFFICULTY_SCALE_FACTOR = 3.0e-5; private static final double DIFFICULTY_SCALE_FACTOR = 3.0e-5;
EquihashProofOfWorkService(int version) { EquihashProofOfWorkService(int version) {
@ -39,15 +39,15 @@ public class EquihashProofOfWorkService extends ProofOfWorkService {
} }
@Override @Override
public CompletableFuture<ProofOfWork> mint(String itemId, byte[] challenge, int log2Difficulty) { public CompletableFuture<ProofOfWork> mint(String itemId, byte[] challenge, double difficulty) {
double difficulty = adjustedDifficulty(log2Difficulty); double scaledDifficulty = scaledDifficulty(difficulty);
log.info("Got adjusted difficulty: {}", difficulty); log.info("Got scaled & adjusted difficulty: {}", scaledDifficulty);
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
long ts = System.currentTimeMillis(); long ts = System.currentTimeMillis();
byte[] solution = new Equihash(90, 5, difficulty).puzzle(challenge).findSolution().serialize(); byte[] solution = new Equihash(90, 5, scaledDifficulty).puzzle(challenge).findSolution().serialize();
long counter = Longs.fromByteArray(Arrays.copyOf(solution, 8)); long counter = Longs.fromByteArray(Arrays.copyOf(solution, 8));
var proofOfWork = new ProofOfWork(solution, counter, challenge, log2Difficulty, var proofOfWork = new ProofOfWork(solution, counter, challenge, difficulty,
System.currentTimeMillis() - ts, getVersion()); System.currentTimeMillis() - ts, getVersion());
log.info("Completed minting proofOfWork: {}", proofOfWork); log.info("Completed minting proofOfWork: {}", proofOfWork);
return proofOfWork; return proofOfWork;
@ -63,14 +63,14 @@ public class EquihashProofOfWorkService extends ProofOfWorkService {
@Override @Override
boolean verify(ProofOfWork proofOfWork) { boolean verify(ProofOfWork proofOfWork) {
double difficulty = adjustedDifficulty(proofOfWork.getNumLeadingZeros()); double scaledDifficulty = scaledDifficulty(proofOfWork.getDifficulty());
var puzzle = new Equihash(90, 5, difficulty).puzzle(proofOfWork.getChallenge()); var puzzle = new Equihash(90, 5, scaledDifficulty).puzzle(proofOfWork.getChallenge());
return puzzle.deserializeSolution(proofOfWork.getPayload()).verify(); return puzzle.deserializeSolution(proofOfWork.getPayload()).verify();
} }
private static double adjustedDifficulty(int log2Difficulty) { private static double scaledDifficulty(double difficulty) {
return Equihash.adjustDifficulty(Math.scalb(DIFFICULTY_SCALE_FACTOR, log2Difficulty), return Equihash.adjustDifficulty(DIFFICULTY_SCALE_FACTOR * difficulty,
Equihash.EQUIHASH_n_5_MEAN_SOLUTION_COUNT_PER_NONCE); Equihash.EQUIHASH_n_5_MEAN_SOLUTION_COUNT_PER_NONCE);
} }
} }

View File

@ -45,9 +45,9 @@ public class HashCashService extends ProofOfWorkService {
} }
@Override @Override
public CompletableFuture<ProofOfWork> mint(String itemId, byte[] challenge, int log2Difficulty) { public CompletableFuture<ProofOfWork> mint(String itemId, byte[] challenge, double difficulty) {
byte[] payload = getBytes(itemId); byte[] payload = getBytes(itemId);
return mint(payload, challenge, log2Difficulty); return mint(payload, challenge, difficulty);
} }
@Override @Override
@ -57,7 +57,7 @@ public class HashCashService extends ProofOfWorkService {
static CompletableFuture<ProofOfWork> mint(byte[] payload, static CompletableFuture<ProofOfWork> mint(byte[] payload,
byte[] challenge, byte[] challenge,
int difficulty) { double difficulty) {
return HashCashService.mint(payload, return HashCashService.mint(payload,
challenge, challenge,
difficulty, difficulty,
@ -68,33 +68,33 @@ public class HashCashService extends ProofOfWorkService {
boolean verify(ProofOfWork proofOfWork) { boolean verify(ProofOfWork proofOfWork) {
return verify(proofOfWork, return verify(proofOfWork,
proofOfWork.getChallenge(), proofOfWork.getChallenge(),
proofOfWork.getNumLeadingZeros()); toNumLeadingZeros(proofOfWork.getDifficulty()));
} }
static boolean verify(ProofOfWork proofOfWork, static boolean verify(ProofOfWork proofOfWork,
byte[] controlChallenge, byte[] controlChallenge,
int controlDifficulty) { int controlLog2Difficulty) {
return HashCashService.verify(proofOfWork, return HashCashService.verify(proofOfWork,
controlChallenge, controlChallenge,
controlDifficulty, controlLog2Difficulty,
HashCashService::testDifficulty); HashCashService::testDifficulty);
} }
static boolean verify(ProofOfWork proofOfWork, static boolean verify(ProofOfWork proofOfWork,
byte[] controlChallenge, byte[] controlChallenge,
int controlDifficulty, int controlLog2Difficulty,
BiPredicate<byte[], byte[]> challengeValidation, BiPredicate<byte[], byte[]> challengeValidation,
BiPredicate<Integer, Integer> difficultyValidation) { BiPredicate<Integer, Integer> difficultyValidation) {
return HashCashService.verify(proofOfWork, return HashCashService.verify(proofOfWork,
controlChallenge, controlChallenge,
controlDifficulty, controlLog2Difficulty,
challengeValidation, challengeValidation,
difficultyValidation, difficultyValidation,
HashCashService::testDifficulty); HashCashService::testDifficulty);
} }
private static boolean testDifficulty(byte[] result, long difficulty) { private static boolean testDifficulty(byte[] result, int log2Difficulty) {
return HashCashService.numberOfLeadingZeros(result) > difficulty; return HashCashService.numberOfLeadingZeros(result) > log2Difficulty;
} }
@ -104,16 +104,17 @@ public class HashCashService extends ProofOfWorkService {
static CompletableFuture<ProofOfWork> mint(byte[] payload, static CompletableFuture<ProofOfWork> mint(byte[] payload,
byte[] challenge, byte[] challenge,
int difficulty, double difficulty,
BiPredicate<byte[], Integer> testDifficulty) { BiPredicate<byte[], Integer> testDifficulty) {
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
long ts = System.currentTimeMillis(); long ts = System.currentTimeMillis();
int log2Difficulty = toNumLeadingZeros(difficulty);
byte[] result; byte[] result;
long counter = 0; long counter = 0;
do { do {
result = toSha256Hash(payload, challenge, ++counter); result = toSha256Hash(payload, challenge, ++counter);
} }
while (!testDifficulty.test(result, difficulty)); while (!testDifficulty.test(result, log2Difficulty));
ProofOfWork proofOfWork = new ProofOfWork(payload, counter, challenge, difficulty, System.currentTimeMillis() - ts, 0); ProofOfWork proofOfWork = new ProofOfWork(payload, counter, challenge, difficulty, System.currentTimeMillis() - ts, 0);
log.info("Completed minting proofOfWork: {}", proofOfWork); log.info("Completed minting proofOfWork: {}", proofOfWork);
return proofOfWork; return proofOfWork;
@ -122,11 +123,11 @@ public class HashCashService extends ProofOfWorkService {
static boolean verify(ProofOfWork proofOfWork, static boolean verify(ProofOfWork proofOfWork,
byte[] controlChallenge, byte[] controlChallenge,
int controlDifficulty, int controlLog2Difficulty,
BiPredicate<byte[], Integer> testDifficulty) { BiPredicate<byte[], Integer> testDifficulty) {
return verify(proofOfWork, return verify(proofOfWork,
controlChallenge, controlChallenge,
controlDifficulty, controlLog2Difficulty,
HashCashService.isChallengeValid, HashCashService.isChallengeValid,
HashCashService.isDifficultyValid, HashCashService.isDifficultyValid,
testDifficulty); testDifficulty);
@ -134,12 +135,12 @@ public class HashCashService extends ProofOfWorkService {
static boolean verify(ProofOfWork proofOfWork, static boolean verify(ProofOfWork proofOfWork,
byte[] controlChallenge, byte[] controlChallenge,
int controlDifficulty, int controlLog2Difficulty,
BiPredicate<byte[], byte[]> challengeValidation, BiPredicate<byte[], byte[]> challengeValidation,
BiPredicate<Integer, Integer> difficultyValidation, BiPredicate<Integer, Integer> difficultyValidation,
BiPredicate<byte[], Integer> testDifficulty) { BiPredicate<byte[], Integer> testDifficulty) {
return challengeValidation.test(proofOfWork.getChallenge(), controlChallenge) && return challengeValidation.test(proofOfWork.getChallenge(), controlChallenge) &&
difficultyValidation.test(proofOfWork.getNumLeadingZeros(), controlDifficulty) && difficultyValidation.test(toNumLeadingZeros(proofOfWork.getDifficulty()), controlLog2Difficulty) &&
verify(proofOfWork, testDifficulty); verify(proofOfWork, testDifficulty);
} }
@ -147,7 +148,7 @@ public class HashCashService extends ProofOfWorkService {
byte[] hash = HashCashService.toSha256Hash(proofOfWork.getPayload(), byte[] hash = HashCashService.toSha256Hash(proofOfWork.getPayload(),
proofOfWork.getChallenge(), proofOfWork.getChallenge(),
proofOfWork.getCounter()); proofOfWork.getCounter());
return testDifficulty.test(hash, proofOfWork.getNumLeadingZeros()); return testDifficulty.test(hash, toNumLeadingZeros(proofOfWork.getDifficulty()));
} }
@ -194,4 +195,10 @@ public class HashCashService extends ProofOfWorkService {
} }
return n - (i >>> 1); return n - (i >>> 1);
} }
// round up to nearest power-of-two and take the base-2 log
@VisibleForTesting
static int toNumLeadingZeros(double difficulty) {
return Math.getExponent(Math.max(Math.nextDown(difficulty), 0.5)) + 1;
}
} }

View File

@ -21,8 +21,6 @@ import bisq.common.proto.network.NetworkPayload;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import java.math.BigInteger;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@ -34,8 +32,8 @@ public final class ProofOfWork implements NetworkPayload {
private final long counter; private final long counter;
@Getter @Getter
private final byte[] challenge; private final byte[] challenge;
// We want to support BigInteger value for difficulty as well so we store it as byte array @Getter
private final byte[] difficulty; private final double difficulty;
@Getter @Getter
private final long duration; private final long duration;
@Getter @Getter
@ -44,37 +42,9 @@ public final class ProofOfWork implements NetworkPayload {
public ProofOfWork(byte[] payload, public ProofOfWork(byte[] payload,
long counter, long counter,
byte[] challenge, byte[] challenge,
int difficulty, double difficulty,
long duration, long duration,
int version) { int version) {
this(payload,
counter,
challenge,
BigInteger.valueOf(difficulty).toByteArray(),
duration,
version);
}
public ProofOfWork(byte[] payload,
long counter,
byte[] challenge,
BigInteger difficulty,
long duration,
int version) {
this(payload,
counter,
challenge,
difficulty.toByteArray(),
duration,
version);
}
private ProofOfWork(byte[] payload,
long counter,
byte[] challenge,
byte[] difficulty,
long duration,
int version) {
this.payload = payload; this.payload = payload;
this.counter = counter; this.counter = counter;
this.challenge = challenge; this.challenge = challenge;
@ -83,10 +53,6 @@ public final class ProofOfWork implements NetworkPayload {
this.version = version; this.version = version;
} }
public int getNumLeadingZeros() {
return new BigInteger(difficulty).intValue();
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER // PROTO BUFFER
@ -98,7 +64,7 @@ public final class ProofOfWork implements NetworkPayload {
.setPayload(ByteString.copyFrom(payload)) .setPayload(ByteString.copyFrom(payload))
.setCounter(counter) .setCounter(counter)
.setChallenge(ByteString.copyFrom(challenge)) .setChallenge(ByteString.copyFrom(challenge))
.setDifficulty(ByteString.copyFrom(difficulty)) .setDifficulty(difficulty)
.setDuration(duration) .setDuration(duration)
.setVersion(version) .setVersion(version)
.build(); .build();
@ -109,7 +75,7 @@ public final class ProofOfWork implements NetworkPayload {
proto.getPayload().toByteArray(), proto.getPayload().toByteArray(),
proto.getCounter(), proto.getCounter(),
proto.getChallenge().toByteArray(), proto.getChallenge().toByteArray(),
proto.getDifficulty().toByteArray(), proto.getDifficulty(),
proto.getDuration(), proto.getDuration(),
proto.getVersion() proto.getVersion()
); );
@ -120,7 +86,7 @@ public final class ProofOfWork implements NetworkPayload {
public String toString() { public String toString() {
return "ProofOfWork{" + return "ProofOfWork{" +
",\r\n counter=" + counter + ",\r\n counter=" + counter +
",\r\n numLeadingZeros=" + getNumLeadingZeros() + ",\r\n difficulty=" + difficulty +
",\r\n duration=" + duration + ",\r\n duration=" + duration +
",\r\n version=" + version + ",\r\n version=" + version +
"\r\n}"; "\r\n}";

View File

@ -45,28 +45,28 @@ public abstract class ProofOfWorkService {
this.version = version; this.version = version;
} }
public abstract CompletableFuture<ProofOfWork> mint(String itemId, byte[] challenge, int log2Difficulty); public abstract CompletableFuture<ProofOfWork> mint(String itemId, byte[] challenge, double difficulty);
public abstract byte[] getChallenge(String itemId, String ownerId); public abstract byte[] getChallenge(String itemId, String ownerId);
abstract boolean verify(ProofOfWork proofOfWork); abstract boolean verify(ProofOfWork proofOfWork);
public CompletableFuture<ProofOfWork> mint(String itemId, String ownerId, int log2Difficulty) { public CompletableFuture<ProofOfWork> mint(String itemId, String ownerId, double difficulty) {
return mint(itemId, getChallenge(itemId, ownerId), log2Difficulty); return mint(itemId, getChallenge(itemId, ownerId), difficulty);
} }
public boolean verify(ProofOfWork proofOfWork, public boolean verify(ProofOfWork proofOfWork,
String itemId, String itemId,
String ownerId, String ownerId,
int controlLog2Difficulty, double controlDifficulty,
BiPredicate<byte[], byte[]> challengeValidation, BiPredicate<byte[], byte[]> challengeValidation,
BiPredicate<Integer, Integer> difficultyValidation) { BiPredicate<Double, Double> difficultyValidation) {
Preconditions.checkArgument(proofOfWork.getVersion() == version); Preconditions.checkArgument(proofOfWork.getVersion() == version);
byte[] controlChallenge = getChallenge(itemId, ownerId); byte[] controlChallenge = getChallenge(itemId, ownerId);
return challengeValidation.test(proofOfWork.getChallenge(), controlChallenge) && return challengeValidation.test(proofOfWork.getChallenge(), controlChallenge) &&
difficultyValidation.test(proofOfWork.getNumLeadingZeros(), controlLog2Difficulty) && difficultyValidation.test(proofOfWork.getDifficulty(), controlDifficulty) &&
verify(proofOfWork); verify(proofOfWork);
} }
} }

View File

@ -32,6 +32,17 @@ public class HashCashServiceTest {
assertEquals(9, HashCashService.numberOfLeadingZeros(new byte[]{Byte.parseByte("00000000", 2), Byte.parseByte("01010000", 2)})); assertEquals(9, HashCashService.numberOfLeadingZeros(new byte[]{Byte.parseByte("00000000", 2), Byte.parseByte("01010000", 2)}));
} }
@Test
public void testToNumLeadingZeros() {
assertEquals(0, HashCashService.toNumLeadingZeros(-1.0));
assertEquals(0, HashCashService.toNumLeadingZeros(0.0));
assertEquals(0, HashCashService.toNumLeadingZeros(1.0));
assertEquals(1, HashCashService.toNumLeadingZeros(1.1));
assertEquals(1, HashCashService.toNumLeadingZeros(2.0));
assertEquals(8, HashCashService.toNumLeadingZeros(256.0));
assertEquals(1024, HashCashService.toNumLeadingZeros(Double.POSITIVE_INFINITY));
}
// @Ignore // @Ignore
@Test @Test
public void testDiffIncrease() throws ExecutionException, InterruptedException { public void testDiffIncrease() throws ExecutionException, InterruptedException {
@ -58,7 +69,8 @@ public class HashCashServiceTest {
//Minting 1000 tokens with 13 leading zeros took 25.276 ms per token and 16786 iterations in average. Verification took 0.002 ms per token. //Minting 1000 tokens with 13 leading zeros took 25.276 ms per token and 16786 iterations in average. Verification took 0.002 ms per token.
} }
private void run(int difficulty, StringBuilder stringBuilder) throws ExecutionException, InterruptedException { private void run(int log2Difficulty, StringBuilder stringBuilder) throws ExecutionException, InterruptedException {
double difficulty = Math.scalb(1.0, log2Difficulty);
int numTokens = 1000; int numTokens = 1000;
byte[] payload = RandomStringUtils.random(50, true, true).getBytes(StandardCharsets.UTF_8); byte[] payload = RandomStringUtils.random(50, true, true).getBytes(StandardCharsets.UTF_8);
long ts = System.currentTimeMillis(); long ts = System.currentTimeMillis();
@ -75,7 +87,7 @@ public class HashCashServiceTest {
double time1 = (System.currentTimeMillis() - ts) / size; double time1 = (System.currentTimeMillis() - ts) / size;
double time2 = (System.currentTimeMillis() - ts2) / size; double time2 = (System.currentTimeMillis() - ts2) / size;
stringBuilder.append("\nMinting ").append(numTokens) stringBuilder.append("\nMinting ").append(numTokens)
.append(" tokens with ").append(difficulty) .append(" tokens with > ").append(log2Difficulty)
.append(" leading zeros took ").append(time1) .append(" leading zeros took ").append(time1)
.append(" ms per token and ").append(averageCounter) .append(" ms per token and ").append(averageCounter)
.append(" iterations in average. Verification took ").append(time2) .append(" iterations in average. Verification took ").append(time2)

View File

@ -105,9 +105,10 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
// added at BsqSwap release // added at BsqSwap release
private final boolean disablePowMessage; private final boolean disablePowMessage;
// Number of leading zeros for pow for BSQ swap offers. Difficulty of 8 requires 0.856 ms in average, 15 about 100 ms. // 2 ** effective-number-of-leading-zeros for pow for BSQ swap offers, when using Hashcash (= version 0), and
// See ProofOfWorkTest for more info. // a similar difficulty for Equihash (= versions 1) or later schemes. Difficulty of 2 ** 8 (= 256) requires
private final int powDifficulty; // 0.856 ms in average, 2 ** 15 (= 32768) about 100 ms. See HashCashServiceTest for more info.
private final double powDifficulty;
// Enabled PoW version numbers in reverse order of preference, starting with 0 for Hashcash. // Enabled PoW version numbers in reverse order of preference, starting with 0 for Hashcash.
private final List<Integer> enabledPowVersions; private final List<Integer> enabledPowVersions;
@ -222,7 +223,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
boolean disableMempoolValidation, boolean disableMempoolValidation,
boolean disableApi, boolean disableApi,
boolean disablePowMessage, boolean disablePowMessage,
int powDifficulty, double powDifficulty,
List<Integer> enabledPowVersions, List<Integer> enabledPowVersions,
long makerFeeBtc, long makerFeeBtc,
long takerFeeBtc, long takerFeeBtc,
@ -300,7 +301,7 @@ public final class Filter implements ProtectedStoragePayload, ExpirablePayload {
boolean disableMempoolValidation, boolean disableMempoolValidation,
boolean disableApi, boolean disableApi,
boolean disablePowMessage, boolean disablePowMessage,
int powDifficulty, double powDifficulty,
List<Integer> enabledPowVersions, List<Integer> enabledPowVersions,
long makerFeeBtc, long makerFeeBtc,
long takerFeeBtc, long takerFeeBtc,

View File

@ -90,7 +90,7 @@ public class FilterManager {
private final BiPredicate<byte[], byte[]> challengeValidation = Arrays::equals; private final BiPredicate<byte[], byte[]> challengeValidation = Arrays::equals;
// We only require a new pow if difficulty has increased // We only require a new pow if difficulty has increased
private final BiPredicate<Integer, Integer> difficultyValidation = private final BiPredicate<Double, Double> difficultyValidation =
(value, controlValue) -> value - controlValue >= 0; (value, controlValue) -> value - controlValue >= 0;

View File

@ -199,8 +199,8 @@ public class OpenBsqSwapOfferService {
NodeAddress makerAddress = Objects.requireNonNull(p2PService.getAddress()); NodeAddress makerAddress = Objects.requireNonNull(p2PService.getAddress());
offerUtil.validateBasicOfferData(PaymentMethod.BSQ_SWAP, "BSQ"); offerUtil.validateBasicOfferData(PaymentMethod.BSQ_SWAP, "BSQ");
int log2Difficulty = getPowDifficulty(); double difficulty = getPowDifficulty();
getPowService().mint(offerId, makerAddress.getFullAddress(), log2Difficulty) getPowService().mint(offerId, makerAddress.getFullAddress(), difficulty)
.whenComplete((proofOfWork, throwable) -> { .whenComplete((proofOfWork, throwable) -> {
// We got called from a non user thread... // We got called from a non user thread...
UserThread.execute(() -> { UserThread.execute(() -> {
@ -347,8 +347,8 @@ public class OpenBsqSwapOfferService {
String newOfferId = OfferUtil.getOfferIdWithMutationCounter(openOffer.getId()); String newOfferId = OfferUtil.getOfferIdWithMutationCounter(openOffer.getId());
NodeAddress nodeAddress = Objects.requireNonNull(openOffer.getOffer().getMakerNodeAddress()); NodeAddress nodeAddress = Objects.requireNonNull(openOffer.getOffer().getMakerNodeAddress());
int log2Difficulty = getPowDifficulty(); double difficulty = getPowDifficulty();
getPowService().mint(newOfferId, nodeAddress.getFullAddress(), log2Difficulty) getPowService().mint(newOfferId, nodeAddress.getFullAddress(), difficulty)
.whenComplete((proofOfWork, throwable) -> { .whenComplete((proofOfWork, throwable) -> {
// We got called from a non user thread... // We got called from a non user thread...
UserThread.execute(() -> { UserThread.execute(() -> {
@ -387,8 +387,8 @@ public class OpenBsqSwapOfferService {
} }
private int getPowDifficulty() { private double getPowDifficulty() {
return filterManager.getFilter() != null ? filterManager.getFilter().getPowDifficulty() : 0; return filterManager.getFilter() != null ? filterManager.getFilter().getPowDifficulty() : 0.0;
} }
private ProofOfWorkService getPowService() { private ProofOfWorkService getPowService() {

View File

@ -187,7 +187,7 @@ public class FilterWindow extends Overlay<FilterWindow> {
Res.get("filterWindow.disablePowMessage")); Res.get("filterWindow.disablePowMessage"));
InputTextField powDifficultyTF = addInputTextField(gridPane, ++rowIndex, InputTextField powDifficultyTF = addInputTextField(gridPane, ++rowIndex,
Res.get("filterWindow.powDifficulty")); Res.get("filterWindow.powDifficulty"));
powDifficultyTF.setText("0"); powDifficultyTF.setText("0.0");
InputTextField enabledPowVersionsTF = addInputTextField(gridPane, ++rowIndex, InputTextField enabledPowVersionsTF = addInputTextField(gridPane, ++rowIndex,
Res.get("filterWindow.enabledPowVersions")); Res.get("filterWindow.enabledPowVersions"));
InputTextField makerFeeBtcTF = addInputTextField(gridPane, ++rowIndex, InputTextField makerFeeBtcTF = addInputTextField(gridPane, ++rowIndex,
@ -270,7 +270,7 @@ public class FilterWindow extends Overlay<FilterWindow> {
disableMempoolValidationCheckBox.isSelected(), disableMempoolValidationCheckBox.isSelected(),
disableApiCheckBox.isSelected(), disableApiCheckBox.isSelected(),
disablePowMessage.isSelected(), disablePowMessage.isSelected(),
Integer.parseInt(powDifficultyTF.getText()), Double.parseDouble(powDifficultyTF.getText()),
readAsList(enabledPowVersionsTF).stream().map(Integer::parseInt).collect(Collectors.toList()), readAsList(enabledPowVersionsTF).stream().map(Integer::parseInt).collect(Collectors.toList()),
ParsingUtils.parseToCoin(makerFeeBtcTF.getText(), btcFormatter).value, ParsingUtils.parseToCoin(makerFeeBtcTF.getText(), btcFormatter).value,
ParsingUtils.parseToCoin(takerFeeBtcTF.getText(), btcFormatter).value, ParsingUtils.parseToCoin(takerFeeBtcTF.getText(), btcFormatter).value,

View File

@ -769,7 +769,7 @@ message Filter {
bool disable_api = 27; bool disable_api = 27;
bool disable_mempool_validation = 28; bool disable_mempool_validation = 28;
bool disable_pow_message = 29; bool disable_pow_message = 29;
int32 pow_difficulty = 30; double pow_difficulty = 30;
repeated int32 enabled_pow_versions = 35; repeated int32 enabled_pow_versions = 35;
int64 maker_fee_btc = 31; int64 maker_fee_btc = 31;
int64 taker_fee_btc = 32; int64 taker_fee_btc = 32;
@ -882,7 +882,7 @@ message ProofOfWork {
bytes payload = 1; bytes payload = 1;
int64 counter = 2; int64 counter = 2;
bytes challenge = 3; bytes challenge = 3;
bytes difficulty = 4; double difficulty = 4;
int64 duration = 5; int64 duration = 5;
int32 version = 6; int32 version = 6;
} }