diff --git a/src/main/java/org/qortal/block/Block.java b/src/main/java/org/qortal/block/Block.java index e1273072..b977a613 100644 --- a/src/main/java/org/qortal/block/Block.java +++ b/src/main/java/org/qortal/block/Block.java @@ -6,6 +6,8 @@ import static java.util.stream.Collectors.toMap; import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -15,6 +17,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.qortal.account.Account; @@ -791,15 +794,46 @@ public class Block { return BigInteger.valueOf(blockSummaryData.getOnlineAccountsCount()).shiftLeft(ACCOUNTS_COUNT_SHIFT).add(keyDistance); } - public static BigInteger calcChainWeight(int commonBlockHeight, byte[] commonBlockSignature, List blockSummaries) { + public static BigInteger calcChainWeight(int commonBlockHeight, byte[] commonBlockSignature, List blockSummaries, int maxHeight) { BigInteger cumulativeWeight = BigInteger.ZERO; int parentHeight = commonBlockHeight; byte[] parentBlockSignature = commonBlockSignature; + NumberFormat formatter = new DecimalFormat("0.###E0"); + boolean isLogging = LOGGER.getLevel().isLessSpecificThan(Level.TRACE); for (BlockSummaryData blockSummaryData : blockSummaries) { - cumulativeWeight = cumulativeWeight.shiftLeft(CHAIN_WEIGHT_SHIFT).add(calcBlockWeight(parentHeight, parentBlockSignature, blockSummaryData)); + StringBuilder stringBuilder = isLogging ? new StringBuilder(512) : null; + + if (isLogging) + stringBuilder.append(formatter.format(cumulativeWeight)).append(" -> "); + + cumulativeWeight = cumulativeWeight.shiftLeft(CHAIN_WEIGHT_SHIFT); + if (isLogging) + stringBuilder.append(formatter.format(cumulativeWeight)).append(" + "); + + BigInteger blockWeight = calcBlockWeight(parentHeight, parentBlockSignature, blockSummaryData); + if (isLogging) + stringBuilder.append("(height: ") + .append(parentHeight + 1) + .append(", online: ") + .append(blockSummaryData.getOnlineAccountsCount()) + .append(") ") + .append(formatter.format(blockWeight)); + + cumulativeWeight = cumulativeWeight.add(blockWeight); + if (isLogging) + stringBuilder.append(" -> ").append(formatter.format(cumulativeWeight)); + + if (isLogging && blockSummaries.size() > 1) + LOGGER.debug(() -> stringBuilder.toString()); //NOSONAR S1612 (false positive?) + parentHeight = blockSummaryData.getHeight(); parentBlockSignature = blockSummaryData.getSignature(); + + /* Potential future consensus change: only comparing the same number of blocks. + if (parentHeight >= maxHeight) + break; + */ } return cumulativeWeight; diff --git a/src/main/java/org/qortal/controller/Synchronizer.java b/src/main/java/org/qortal/controller/Synchronizer.java index 47182119..06850a1b 100644 --- a/src/main/java/org/qortal/controller/Synchronizer.java +++ b/src/main/java/org/qortal/controller/Synchronizer.java @@ -313,12 +313,14 @@ public class Synchronizer { List ourBlockSummaries = repository.getBlockRepository().getBlockSummaries(commonBlockHeight + 1, ourLatestBlockData.getHeight()); // Populate minter account levels for both lists of block summaries - populateBlockSummariesMinterLevels(repository, peerBlockSummaries); populateBlockSummariesMinterLevels(repository, ourBlockSummaries); + populateBlockSummariesMinterLevels(repository, peerBlockSummaries); + + final int mutualHeight = commonBlockHeight - 1 + Math.min(ourBlockSummaries.size(), peerBlockSummaries.size()); // Calculate cumulative chain weights of both blockchain subsets, from common block to highest mutual block. - BigInteger ourChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockSig, ourBlockSummaries); - BigInteger peerChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockSig, peerBlockSummaries); + BigInteger ourChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockSig, ourBlockSummaries, mutualHeight); + BigInteger peerChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockSig, peerBlockSummaries, mutualHeight); NumberFormat formatter = new DecimalFormat("0.###E0"); LOGGER.debug(String.format("Our chain weight: %s, peer's chain weight: %s (higher is better)", formatter.format(ourChainWeight), formatter.format(peerChainWeight))); diff --git a/src/test/java/org/qortal/test/ChainWeightTests.java b/src/test/java/org/qortal/test/ChainWeightTests.java index c580f30c..b02c155e 100644 --- a/src/test/java/org/qortal/test/ChainWeightTests.java +++ b/src/test/java/org/qortal/test/ChainWeightTests.java @@ -103,8 +103,10 @@ public class ChainWeightTests extends Common { populateBlockSummariesMinterLevels(repository, shorterChain); populateBlockSummariesMinterLevels(repository, longerChain); - BigInteger shorterChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockGeneratorKey, shorterChain); - BigInteger longerChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockGeneratorKey, longerChain); + final int mutualHeight = commonBlockHeight - 1 + Math.min(shorterChain.size(), longerChain.size()); + + BigInteger shorterChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockGeneratorKey, shorterChain, mutualHeight); + BigInteger longerChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockGeneratorKey, longerChain, mutualHeight); assertEquals("longer chain should have greater weight", 1, longerChainWeight.compareTo(shorterChainWeight)); }