mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
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:
parent
0c94e232f8
commit
e0595aa284
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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}";
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
@ -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() {
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user