Skip to content

Commit

Permalink
chore: added comments and changed the positions of the files
Browse files Browse the repository at this point in the history
  • Loading branch information
Georgi Grigorov committed Oct 18, 2024
1 parent c00fe3e commit d1eb9f3
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.limechain.babe.api;
package com.limechain.babe;

import com.limechain.utils.math.BigRational;
import com.limechain.chain.lightsyncstate.Authority;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
Expand All @@ -12,19 +13,26 @@
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Authorship {

// threshold = 2^128 * (1 - (1 - c) ^ (authority_weight / sum(authorities_weights)))
public static BigInteger calculatePrimaryThreshold(
@NotNull final Pair<BigInteger, BigInteger> constant,
@NotNull final List<Authority> authorities,
final int authorityIndex) {

if (BigInteger.ZERO.equals(constant.getValue0()) || authorityIndex >= authorities.size()) {
return BigInteger.ZERO;
if (BigInteger.ZERO.equals(constant.getValue1()) ||
authorityIndex >= authorities.size() ||
authorityIndex < 0) {
throw new IllegalArgumentException("Invalid denominator or authority index provided");
}

double numerator = constant.getValue0().doubleValue();
double denominator = constant.getValue1().doubleValue();
double c = numerator / denominator;

if (c > 1 || c < 0) {
throw new IllegalStateException("BABE constant must be within the range (0, 1)");
}

double totalWeight = authorities.stream()
.map(Authority::getWeight)
.reduce(BigInteger.ZERO, BigInteger::add)
Expand All @@ -36,13 +44,16 @@ public static BigInteger calculatePrimaryThreshold(

double theta = weight / totalWeight;

// p = 1 - (1 - c) ^ theta
// p = 1 - (1 - c) ^ theta
double p = 1.0 - Math.pow((1.0 - c), theta);

BigRational pRational = new BigRational(p);

// 1<<128 == 2^128
BigInteger twoToThe128 = BigInteger.ONE.shiftLeft(128);
BigInteger scaledNumer = twoToThe128.multiply(pRational.getNumerator());
BigInteger result = scaledNumer.divide(pRational.getDenominator());

return scaledNumer.divide(pRational.getDenominator());
return result;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package com.limechain.babe.api;
package com.limechain.utils.math;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.math.BigInteger;

/**
* Used to represent quotient a/b of arbitrary precision.
* The implementation is derived from the standard Go math/big package.
*/
@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BigRational {

private BigInteger numerator;
Expand All @@ -15,12 +22,14 @@ public BigRational(double f) {
}

private void fromDouble(double f) {
//0x7FF = 2047
final int expMask = 0x7FF;
long bits = Double.doubleToLongBits(f);
long mantissa = bits & ((1L << 52) - 1);
int exp = (int) ((bits >> 52) & expMask);

switch (exp) {
//non-finite cases result in numerator and denominator equal null
case expMask:
return;
case 0:
Expand All @@ -32,25 +41,20 @@ private void fromDouble(double f) {
break;
}

// Calculate the shift based on the exponent
int shift = 52 - exp;

// Normalize the mantissa
while ((mantissa & 1) == 0 && shift > 0) {
mantissa >>= 1;
shift--;
}

// Set the numerator and denominator
this.numerator = f < 0 ? BigInteger.valueOf((-1) * mantissa) : BigInteger.valueOf(mantissa);
this.denominator = BigInteger.ONE;

// Adjust the denominator based on the shift
if (shift > 0) {
this.denominator = this.denominator.shiftLeft(shift);
} else {
this.numerator = this.numerator.shiftLeft((-1) * shift);
}

}
}
88 changes: 88 additions & 0 deletions src/test/java/com/limechain/babe/AuthorshipTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.limechain.babe;

import com.limechain.chain.lightsyncstate.Authority;
import org.javatuples.Pair;
import org.junit.jupiter.api.Test;

import java.math.BigInteger;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class AuthorshipTest {

@Test
void testCalculatePrimaryThreshold() {
var constant = new Pair<>(BigInteger.ONE, BigInteger.valueOf(4));
Authority authority1 = new Authority(new byte[32], BigInteger.ONE);
Authority authority2 = new Authority(new byte[32], BigInteger.ONE);
Authority authority3 = new Authority(new byte[32], BigInteger.ONE);

var authorities = List.of(authority1, authority2, authority3);
var result = Authorship.calculatePrimaryThreshold(constant, authorities, 0);
assertEquals(new BigInteger("31115318766088776340791719032032067584"), result);
}


@Test
void testCalculatePrimaryThresholdWithConstantNumeratorEqualsZero() {
var constant = new Pair<>(BigInteger.ZERO, BigInteger.valueOf(4));
Authority authority1 = new Authority(new byte[32], BigInteger.ONE);
Authority authority2 = new Authority(new byte[32], BigInteger.ONE);
Authority authority3 = new Authority(new byte[32], BigInteger.ONE);

var authorities = List.of(authority1, authority2, authority3);
var result = Authorship.calculatePrimaryThreshold(constant, authorities, 0);
assertEquals(new BigInteger("0"), result);
}

@Test
void testCalculatePrimaryThresholdWithConstantDenominatorEqualsZero() {
var constant = new Pair<>(BigInteger.ONE, BigInteger.ZERO);
Authority authority1 = new Authority(new byte[32], BigInteger.ONE);
Authority authority2 = new Authority(new byte[32], BigInteger.ONE);
Authority authority3 = new Authority(new byte[32], BigInteger.ONE);

var authorities = List.of(authority1, authority2, authority3);
assertThrows(IllegalArgumentException.class,
() -> Authorship.calculatePrimaryThreshold(constant, authorities, 0));
}

@Test
void testCalculatePrimaryThresholdWithBabeConstantOutOfRange() {
var constant = new Pair<>(BigInteger.TEN, BigInteger.ONE);
Authority authority1 = new Authority(new byte[32], BigInteger.ONE);
Authority authority2 = new Authority(new byte[32], BigInteger.ONE);
Authority authority3 = new Authority(new byte[32], BigInteger.ONE);

var authorities = List.of(authority1, authority2, authority3);
assertThrows(IllegalStateException.class,
() -> Authorship.calculatePrimaryThreshold(constant, authorities, 0));
}

@Test
void testCalculatePrimaryThresholdWithAuthorityIndexOutOfBounds() {
var constant = new Pair<>(BigInteger.ONE, BigInteger.valueOf(4));
Authority authority1 = new Authority(new byte[32], BigInteger.ONE);
Authority authority2 = new Authority(new byte[32], BigInteger.ONE);
Authority authority3 = new Authority(new byte[32], BigInteger.ONE);

var authorities = List.of(authority1, authority2, authority3);
var nonExistingIndex = Integer.MAX_VALUE;
assertThrows(IllegalArgumentException.class,
() -> Authorship.calculatePrimaryThreshold(constant, authorities, nonExistingIndex));
}

@Test
void testCalculatePrimaryThresholdWithNegativeAuthorityIndex() {
var constant = new Pair<>(BigInteger.ONE, BigInteger.valueOf(4));
Authority authority1 = new Authority(new byte[32], BigInteger.ONE);
Authority authority2 = new Authority(new byte[32], BigInteger.ONE);
Authority authority3 = new Authority(new byte[32], BigInteger.ONE);

var authorities = List.of(authority1, authority2, authority3);
assertThrows(IllegalArgumentException.class,
() -> Authorship.calculatePrimaryThreshold(constant, authorities, -1));
}
}
26 changes: 0 additions & 26 deletions src/test/java/com/limechain/utils/AuthorshipTest.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package com.limechain.utils;
package com.limechain.utils.math;

import com.limechain.babe.api.BigRational;
import org.junit.jupiter.api.Test;

import java.math.BigInteger;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

public class BigRationalTest {
class BigRationalTest {

@Test
void testBigRational() {
Expand Down

0 comments on commit d1eb9f3

Please sign in to comment.