Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change difficulty calculation #1703

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,21 @@ public HashCashTokenService(HashCashProofOfWorkService proofOfWorkService) {
}

@Override
public HashCashToken createToken(EnvelopePayloadMessage message, NetworkLoad networkLoad, String peerAddress, int messageCounter) {
public HashCashToken createToken(EnvelopePayloadMessage message,
NetworkLoad networkLoad,
String peerAddress,
int messageCounter) {
long ts = System.currentTimeMillis();
double difficulty = calculateDifficulty(message, networkLoad);
byte[] challenge = getChallenge(peerAddress, messageCounter);
byte[] payload = getPayload(message);
HashCashToken token = proofOfWorkService.mint(payload, challenge, difficulty)
.thenApply(proofOfWork -> new HashCashToken(proofOfWork, messageCounter))
.join();
log.debug("Create token for {} took {} ms\n token={}, peersLoad={}, peerAddress={}",
message.getClass().getSimpleName(), System.currentTimeMillis() - ts, token, networkLoad, peerAddress);
ProofOfWork proofOfWork = proofOfWorkService.mint(payload, challenge, difficulty);
HashCashToken token = new HashCashToken(proofOfWork, messageCounter);
log.info("Create HashCashToken for {} took {} ms\n" +
"CostFactor={}; Load={}; Difficulty=2^{}={}",
message.getClass().getSimpleName(), System.currentTimeMillis() - ts,
message.getCostFactor(), networkLoad.getValue(),
MathUtils.roundDouble(Math.log(difficulty) / MathUtils.LOG2, 2), difficulty);
return token;
}

Expand Down Expand Up @@ -186,10 +191,7 @@ private byte[] getChallenge(String peerAddress, int messageCounter) {
private double calculateDifficulty(EnvelopePayloadMessage message, NetworkLoad networkLoad) {
double messageCostFactor = MathUtils.bounded(0.01, 1, message.getCostFactor());
double loadValue = MathUtils.bounded(0.01, 1, networkLoad.getValue());
double difficulty = MAX_DIFFICULTY * messageCostFactor + MAX_DIFFICULTY * loadValue;
log.debug("calculated difficulty={}, Math.pow(2, {}), messageCostFactor={}, loadValue={}",
difficulty, MathUtils.roundDouble(Math.log(difficulty) / MathUtils.LOG2, 2),
messageCostFactor, loadValue);
double difficulty = MAX_DIFFICULTY * messageCostFactor * loadValue;
return MathUtils.bounded(MIN_DIFFICULTY, MAX_DIFFICULTY, difficulty);
}
}
16 changes: 11 additions & 5 deletions security/src/main/java/bisq/security/pow/ProofOfWorkService.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ public abstract class ProofOfWorkService {
public ProofOfWorkService() {
}

public abstract CompletableFuture<ProofOfWork> mint(byte[] payload, byte[] challenge, double difficulty);
public CompletableFuture<ProofOfWork> mintAsync(byte[] payload,
byte[] challenge,
double difficulty) {
return CompletableFuture.supplyAsync(() -> mint(payload, challenge, difficulty));
}

public abstract ProofOfWork mint(byte[] payload, byte[] challenge, double difficulty);

public abstract boolean verify(ProofOfWork proofOfWork);

Expand All @@ -44,16 +50,16 @@ public byte[] asUtf8Bytes(String itemId) {

public abstract byte[] getChallenge(String itemId, String ownerId);

public CompletableFuture<ProofOfWork> mint(String itemId, String ownerId, double difficulty) {
return mint(asUtf8Bytes(itemId), getChallenge(itemId, ownerId), difficulty);
public CompletableFuture<ProofOfWork> mintAsync(String itemId, String ownerId, double difficulty) {
return mintAsync(asUtf8Bytes(itemId), getChallenge(itemId, ownerId), difficulty);
}

public CompletableFuture<ProofOfWork> mintNymProofOfWork(byte[] pubKeyHash) {
return mintNymProofOfWork(pubKeyHash, MINT_NYM_DIFFICULTY);
}

public CompletableFuture<ProofOfWork> mintNymProofOfWork(byte[] pubKeyHash, double nymDifficulty) {
return mint(pubKeyHash, null, nymDifficulty);
return mintAsync(pubKeyHash, null, nymDifficulty);
}

public boolean verify(ProofOfWork proofOfWork,
Expand All @@ -76,7 +82,7 @@ private void printStatistics() {
long ts = System.currentTimeMillis();
byte[] bytes = new byte[1024];
new Random().nextBytes(bytes);
mint(bytes, null, diff).join();
mintAsync(bytes, null, diff).join();
tsList.add(System.currentTimeMillis() - ts);
}
double average = tsList.stream().mapToLong(e -> e).average().getAsDouble();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;

// TODO the scaling of the difficulty does not provide the expected results
// Borrowed from: https://github.com/bisq-network/bisq
Expand All @@ -43,20 +42,18 @@ public EquihashProofOfWorkService() {
}

@Override
public CompletableFuture<ProofOfWork> mint(byte[] payload, @Nullable byte[] challenge, double difficulty) {
public ProofOfWork mint(byte[] payload, @Nullable byte[] challenge, double difficulty) {
double scaledDifficulty = scaledDifficulty(difficulty);
log.debug("Got scaled & adjusted difficulty: {}", scaledDifficulty);

return CompletableFuture.supplyAsync(() -> {
long ts = System.currentTimeMillis();
byte[] seed = getSeed(payload, challenge);
byte[] solution = new Equihash(90, 5, scaledDifficulty).puzzle(seed).findSolution().serialize();
long counter = Longs.fromByteArray(Arrays.copyOf(solution, 8));
long duration = System.currentTimeMillis() - ts;
var proofOfWork = new ProofOfWork(payload, counter, challenge, difficulty, solution, duration);
log.debug("Completed minting proofOfWork: {}. {} iterations took {} ms.", proofOfWork, counter, duration);
return proofOfWork;
});
long ts = System.currentTimeMillis();
byte[] seed = getSeed(payload, challenge);
byte[] solution = new Equihash(90, 5, scaledDifficulty).puzzle(seed).findSolution().serialize();
long counter = Longs.fromByteArray(Arrays.copyOf(solution, 8));
long duration = System.currentTimeMillis() - ts;
var proofOfWork = new ProofOfWork(payload, counter, challenge, difficulty, solution, duration);
log.debug("Completed minting proofOfWork: {}. {} iterations took {} ms.", proofOfWork, counter, duration);
return proofOfWork;
}

private byte[] getSeed(byte[] payload, @Nullable byte[] challenge) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,38 +25,34 @@
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;

/**
* HashCash implementation for proof of work
* It doubles required work by log2Difficulty increase (adding one leading zero).
* <p>
* See https://www.hashcash.org/papers/hashcash.pdf
* See <a href="https://www.hashcash.org/papers/hashcash.pdf">hashcash.pdf</a>
*/
@Slf4j
public class HashCashProofOfWorkService extends ProofOfWorkService {
public HashCashProofOfWorkService() {
}

@Override
public CompletableFuture<ProofOfWork> mint(byte[] payload,
byte[] challenge,
double difficulty) {
return CompletableFuture.supplyAsync(() -> {
long ts = System.currentTimeMillis();
int log2Difficulty = toNumLeadingZeros(difficulty);
byte[] hash;
long counter = 0;
do {
hash = toSha256Hash(payload, challenge, ++counter);
}
while (numberOfLeadingZeros(hash) <= log2Difficulty);
byte[] solution = Longs.toByteArray(counter);
ProofOfWork proofOfWork = new ProofOfWork(payload, counter, challenge, difficulty, solution,
System.currentTimeMillis() - ts);
log.debug("Completed minting proofOfWork: {}", proofOfWork);
return proofOfWork;
});
public ProofOfWork mint(byte[] payload,
byte[] challenge,
double difficulty) {
long ts = System.currentTimeMillis();
int log2Difficulty = toNumLeadingZeros(difficulty);
byte[] hash;
long counter = 0;
do {
hash = toSha256Hash(payload, challenge, ++counter);
}
while (numberOfLeadingZeros(hash) <= log2Difficulty);
byte[] solution = Longs.toByteArray(counter);
ProofOfWork proofOfWork = new ProofOfWork(payload, counter, challenge, difficulty, solution,
System.currentTimeMillis() - ts);
return proofOfWork;
}

@Override
Expand Down
Loading