mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Inline predicates to simplify HashCashService & FilterManager
Remove all the 'challengeValidation', 'difficultyValidation' and 'testDifficulty' BiPredicate method params from 'HashCashService' & 'ProofOfWorkService', to simplify the API. These were originally included to aid testing, but turned out to be unnecessary. Patches committed on behalf of @chimp1984.
This commit is contained in:
parent
772cd74ab2
commit
92209c3ed7
@ -22,24 +22,18 @@ import com.google.common.primitives.Longs;
|
|||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.BiPredicate;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HashCash implementation for proof of work
|
* HashCash implementation for proof of work
|
||||||
* It doubles required work by difficulty increase (adding one leading zero).
|
* It doubles required work by log2Difficulty increase (adding one leading zero).
|
||||||
*
|
*
|
||||||
* See https://www.hashcash.org/papers/hashcash.pdf
|
* See https://www.hashcash.org/papers/hashcash.pdf
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class HashCashService extends ProofOfWorkService {
|
public class HashCashService extends ProofOfWorkService {
|
||||||
// Default validations. Custom implementations might use tolerance.
|
|
||||||
private static final BiPredicate<byte[], byte[]> isChallengeValid = Arrays::equals;
|
|
||||||
private static final BiPredicate<Integer, Integer> isDifficultyValid = Integer::equals;
|
|
||||||
|
|
||||||
HashCashService() {
|
HashCashService() {
|
||||||
super(0);
|
super(0);
|
||||||
}
|
}
|
||||||
@ -50,105 +44,35 @@ public class HashCashService extends ProofOfWorkService {
|
|||||||
return mint(payload, challenge, difficulty);
|
return mint(payload, challenge, difficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public CompletableFuture<ProofOfWork> mint(byte[] payload,
|
||||||
public byte[] getChallenge(String itemId, String ownerId) {
|
|
||||||
return getBytes(itemId + ownerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CompletableFuture<ProofOfWork> mint(byte[] payload,
|
|
||||||
byte[] challenge,
|
byte[] challenge,
|
||||||
double difficulty) {
|
double difficulty) {
|
||||||
return HashCashService.mint(payload,
|
|
||||||
challenge,
|
|
||||||
difficulty,
|
|
||||||
HashCashService::testDifficulty);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean verify(ProofOfWork proofOfWork) {
|
|
||||||
return verify(proofOfWork,
|
|
||||||
proofOfWork.getChallenge(),
|
|
||||||
toNumLeadingZeros(proofOfWork.getDifficulty()));
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean verify(ProofOfWork proofOfWork,
|
|
||||||
byte[] controlChallenge,
|
|
||||||
int controlLog2Difficulty) {
|
|
||||||
return HashCashService.verify(proofOfWork,
|
|
||||||
controlChallenge,
|
|
||||||
controlLog2Difficulty,
|
|
||||||
HashCashService::testDifficulty);
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean verify(ProofOfWork proofOfWork,
|
|
||||||
byte[] controlChallenge,
|
|
||||||
int controlLog2Difficulty,
|
|
||||||
BiPredicate<byte[], byte[]> challengeValidation,
|
|
||||||
BiPredicate<Integer, Integer> difficultyValidation) {
|
|
||||||
return HashCashService.verify(proofOfWork,
|
|
||||||
controlChallenge,
|
|
||||||
controlLog2Difficulty,
|
|
||||||
challengeValidation,
|
|
||||||
difficultyValidation,
|
|
||||||
HashCashService::testDifficulty);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean testDifficulty(byte[] result, int log2Difficulty) {
|
|
||||||
return HashCashService.numberOfLeadingZeros(result) > log2Difficulty;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Generic
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static CompletableFuture<ProofOfWork> mint(byte[] payload,
|
|
||||||
byte[] challenge,
|
|
||||||
double difficulty,
|
|
||||||
BiPredicate<byte[], Integer> testDifficulty) {
|
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
long ts = System.currentTimeMillis();
|
long ts = System.currentTimeMillis();
|
||||||
int log2Difficulty = toNumLeadingZeros(difficulty);
|
int log2Difficulty = toNumLeadingZeros(difficulty);
|
||||||
byte[] result;
|
byte[] hash;
|
||||||
long counter = 0;
|
long counter = 0;
|
||||||
do {
|
do {
|
||||||
result = toSha256Hash(payload, challenge, ++counter);
|
hash = toSha256Hash(payload, challenge, ++counter);
|
||||||
}
|
}
|
||||||
while (!testDifficulty.test(result, log2Difficulty));
|
while (numberOfLeadingZeros(hash) <= 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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean verify(ProofOfWork proofOfWork,
|
@Override
|
||||||
byte[] controlChallenge,
|
boolean verify(ProofOfWork proofOfWork) {
|
||||||
int controlLog2Difficulty,
|
byte[] hash = toSha256Hash(proofOfWork.getPayload(),
|
||||||
BiPredicate<byte[], Integer> testDifficulty) {
|
|
||||||
return verify(proofOfWork,
|
|
||||||
controlChallenge,
|
|
||||||
controlLog2Difficulty,
|
|
||||||
HashCashService.isChallengeValid,
|
|
||||||
HashCashService.isDifficultyValid,
|
|
||||||
testDifficulty);
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean verify(ProofOfWork proofOfWork,
|
|
||||||
byte[] controlChallenge,
|
|
||||||
int controlLog2Difficulty,
|
|
||||||
BiPredicate<byte[], byte[]> challengeValidation,
|
|
||||||
BiPredicate<Integer, Integer> difficultyValidation,
|
|
||||||
BiPredicate<byte[], Integer> testDifficulty) {
|
|
||||||
return challengeValidation.test(proofOfWork.getChallenge(), controlChallenge) &&
|
|
||||||
difficultyValidation.test(toNumLeadingZeros(proofOfWork.getDifficulty()), controlLog2Difficulty) &&
|
|
||||||
verify(proofOfWork, testDifficulty);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean verify(ProofOfWork proofOfWork, BiPredicate<byte[], Integer> testDifficulty) {
|
|
||||||
byte[] hash = HashCashService.toSha256Hash(proofOfWork.getPayload(),
|
|
||||||
proofOfWork.getChallenge(),
|
proofOfWork.getChallenge(),
|
||||||
proofOfWork.getCounter());
|
proofOfWork.getCounter());
|
||||||
return testDifficulty.test(hash, toNumLeadingZeros(proofOfWork.getDifficulty()));
|
return numberOfLeadingZeros(hash) > toNumLeadingZeros(proofOfWork.getDifficulty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getChallenge(String itemId, String ownerId) {
|
||||||
|
return getBytes(itemId + ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,9 +19,9 @@ package bisq.common.crypto;
|
|||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.BiPredicate;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@ -58,15 +58,13 @@ public abstract class ProofOfWorkService {
|
|||||||
public boolean verify(ProofOfWork proofOfWork,
|
public boolean verify(ProofOfWork proofOfWork,
|
||||||
String itemId,
|
String itemId,
|
||||||
String ownerId,
|
String ownerId,
|
||||||
double controlDifficulty,
|
double controlDifficulty) {
|
||||||
BiPredicate<byte[], byte[]> challengeValidation,
|
|
||||||
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 Arrays.equals(proofOfWork.getChallenge(), controlChallenge) &&
|
||||||
difficultyValidation.test(proofOfWork.getDifficulty(), controlDifficulty) &&
|
proofOfWork.getDifficulty() >= controlDifficulty &&
|
||||||
verify(proofOfWork);
|
verify(proofOfWork);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ public class HashCashServiceTest {
|
|||||||
List<ProofOfWork> tokens = new ArrayList<>();
|
List<ProofOfWork> tokens = new ArrayList<>();
|
||||||
for (int i = 0; i < numTokens; i++) {
|
for (int i = 0; i < numTokens; i++) {
|
||||||
byte[] challenge = UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8);
|
byte[] challenge = UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8);
|
||||||
tokens.add(HashCashService.mint(payload, challenge, difficulty).get());
|
tokens.add(new HashCashService().mint(payload, challenge, difficulty).get());
|
||||||
}
|
}
|
||||||
double size = tokens.size();
|
double size = tokens.size();
|
||||||
long ts2 = System.currentTimeMillis();
|
long ts2 = System.currentTimeMillis();
|
||||||
|
@ -37,9 +37,9 @@ import bisq.common.app.DevEnv;
|
|||||||
import bisq.common.app.Version;
|
import bisq.common.app.Version;
|
||||||
import bisq.common.config.Config;
|
import bisq.common.config.Config;
|
||||||
import bisq.common.config.ConfigFileEditor;
|
import bisq.common.config.ConfigFileEditor;
|
||||||
import bisq.common.crypto.ProofOfWorkService;
|
|
||||||
import bisq.common.crypto.KeyRing;
|
import bisq.common.crypto.KeyRing;
|
||||||
import bisq.common.crypto.ProofOfWork;
|
import bisq.common.crypto.ProofOfWork;
|
||||||
|
import bisq.common.crypto.ProofOfWorkService;
|
||||||
|
|
||||||
import org.bitcoinj.core.ECKey;
|
import org.bitcoinj.core.ECKey;
|
||||||
import org.bitcoinj.core.Sha256Hash;
|
import org.bitcoinj.core.Sha256Hash;
|
||||||
@ -58,7 +58,6 @@ import java.nio.charset.StandardCharsets;
|
|||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -66,7 +65,6 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.function.BiPredicate;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
@ -88,12 +86,6 @@ public class FilterManager {
|
|||||||
private static final String BANNED_SEED_NODES = "bannedSeedNodes";
|
private static final String BANNED_SEED_NODES = "bannedSeedNodes";
|
||||||
private static final String BANNED_BTC_NODES = "bannedBtcNodes";
|
private static final String BANNED_BTC_NODES = "bannedBtcNodes";
|
||||||
|
|
||||||
private final BiPredicate<byte[], byte[]> challengeValidation = Arrays::equals;
|
|
||||||
// We only require a new pow if difficulty has increased
|
|
||||||
private final BiPredicate<Double, Double> difficultyValidation =
|
|
||||||
(value, controlValue) -> value - controlValue >= 0;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Listener
|
// Listener
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -506,9 +498,7 @@ public class FilterManager {
|
|||||||
}
|
}
|
||||||
return service.get().verify(offer.getBsqSwapOfferPayload().get().getProofOfWork(),
|
return service.get().verify(offer.getBsqSwapOfferPayload().get().getProofOfWork(),
|
||||||
offer.getId(), offer.getOwnerNodeAddress().toString(),
|
offer.getId(), offer.getOwnerNodeAddress().toString(),
|
||||||
filter.getPowDifficulty(),
|
filter.getPowDifficulty());
|
||||||
challengeValidation,
|
|
||||||
difficultyValidation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Integer> getEnabledPowVersions() {
|
public List<Integer> getEnabledPowVersions() {
|
||||||
|
Loading…
Reference in New Issue
Block a user