mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Use TreeMap to prevent potential nondeterminism in BM share summation
Replace HashMap in 'BurningManService.getBurningManCandidatesByName' result construction with a TreeMap, to ensure that the map values are ordered deterministically (alphabetically by candidate name) when computing floating point sums. The map values are streamed over in a few places in this method and elsewhere in 'DelayedPayoutTxReceiverService', when performing double precision summation to compute the DPT. This introduces potential nondeterminism due to the nonassociativity of FP addition, making sums dependent on the term order. (Note that 'DoubleStream::sum' uses compensated (Kahan) summation, which makes it effectively quad precision internally, so the chance of term reordering causing the result to differ by even a single ULP is probably quite low here. So there might not be much problem in practice.)
This commit is contained in:
parent
c234c2351c
commit
7dfd6aa5e1
@ -48,6 +48,7 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -111,7 +112,7 @@ public class BurningManService {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Map<String, BurningManCandidate> getBurningManCandidatesByName(int chainHeight) {
|
||||
Map<String, BurningManCandidate> burningManCandidatesByName = new HashMap<>();
|
||||
Map<String, BurningManCandidate> burningManCandidatesByName = new TreeMap<>();
|
||||
Map<P2PDataStorage.ByteArray, Set<TxOutput>> proofOfBurnOpReturnTxOutputByHash = getProofOfBurnOpReturnTxOutputByHash(chainHeight);
|
||||
|
||||
// Add contributors who made a compensation request
|
||||
@ -120,8 +121,7 @@ public class BurningManService {
|
||||
.forEach(issuance -> {
|
||||
getCompensationProposalsForIssuance(issuance).forEach(compensationProposal -> {
|
||||
String name = compensationProposal.getName();
|
||||
burningManCandidatesByName.putIfAbsent(name, new BurningManCandidate());
|
||||
BurningManCandidate candidate = burningManCandidatesByName.get(name);
|
||||
BurningManCandidate candidate = burningManCandidatesByName.computeIfAbsent(name, n -> new BurningManCandidate());
|
||||
|
||||
// Issuance
|
||||
Optional<String> customAddress = compensationProposal.getBurningManReceiverAddress();
|
||||
|
Loading…
Reference in New Issue
Block a user