Skip to content

Commit

Permalink
Add age-based boost factor to all reputation sources
Browse files Browse the repository at this point in the history
  • Loading branch information
HenrikJannsen committed Sep 3, 2024
1 parent 294f1d2 commit eaccf81
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ protected void onViewAttached() {
closeButton.setOnAction(e -> controller.onClose());

root.setPrefWidth(OverlayModel.WIDTH);
root.setPrefHeight(OverlayModel.HEIGHT + 80);
root.setPrefHeight(OverlayModel.HEIGHT + 110);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,25 @@

import bisq.common.util.MathUtils;
import bisq.desktop.components.controls.MaterialTextField;
import bisq.desktop.main.content.reputation.build_reputation.components.AgeSlider;
import bisq.i18n.Res;
import bisq.presentation.parser.DoubleParser;
import bisq.user.reputation.BondedReputationService;
import bisq.user.reputation.ProofOfBurnService;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;

import java.util.concurrent.TimeUnit;

public class BondScoreSimulation {

private final Controller controller;
Expand All @@ -48,45 +55,66 @@ public static class Controller implements bisq.desktop.common.view.Controller {
@Getter
private final View view;
private final Model model;
private Subscription scorePin;
private Subscription agePin, ageAsStringPin, amountPin;

private Controller() {
model = new Model();
view = new View(model, this);

model.getAmount().set("100");
model.getAge().set(0);
model.getAgeAsString().set("0");
}

@Override
public void onActivate() {
scorePin = EasyBind.subscribe(model.getAmount(), amount -> model.getScore().set(calculateSimScore(amount)));
agePin = EasyBind.subscribe(model.getAge(), age -> model.getAgeAsString().set(String.valueOf(age)));
ageAsStringPin = EasyBind.subscribe(model.getAgeAsString(), ageAsString -> {
try {
model.getAge().set(Integer.parseInt(ageAsString));
calculateSimScore();
} catch (Exception e) {
}
});
amountPin = EasyBind.subscribe(model.getAmount(), amount -> calculateSimScore());
}

@Override
public void onDeactivate() {
scorePin.unsubscribe();
agePin.unsubscribe();
ageAsStringPin.unsubscribe();
amountPin.unsubscribe();
}

private String calculateSimScore(String value) {
private void calculateSimScore() {
try {
// amountAsLong is the smallest unit of BSQ (100 = 1 BSQ)
long amountAsLong = Math.max(0, MathUtils.roundDoubleToLong(DoubleParser.parse(value) * 100));
long totalScore = BondedReputationService.doCalculateScore(amountAsLong);
return String.valueOf(totalScore);
long amountAsLong = Math.max(0, MathUtils.roundDoubleToLong(DoubleParser.parse(model.getAmount().get()) * 100));
long ageInDays = Math.max(0, model.getAge().get());
long age = TimeUnit.DAYS.toMillis(ageInDays);
long blockTime = System.currentTimeMillis() - age;
long totalScore = BondedReputationService.doCalculateScore(amountAsLong, blockTime);
String score = String.valueOf(totalScore);
model.getScore().set(score);
} catch (Exception e) {
return "";
log.error("Failed to calculate simScore", e);
}
}
}

@Getter
private static class Model implements bisq.desktop.common.view.Model {
private final StringProperty amount = new SimpleStringProperty();
private final IntegerProperty age = new SimpleIntegerProperty();
private final StringProperty ageAsString = new SimpleStringProperty();
private final StringProperty score = new SimpleStringProperty();
}

private static class View extends bisq.desktop.common.view.View<VBox, Model, Controller> {
private final MaterialTextField amount, score;
private final MaterialTextField amount;
private final MaterialTextField score;
private final AgeSlider simAgeSlider;
private final MaterialTextField ageField;

private View(Model model,
Controller controller) {
Expand All @@ -95,23 +123,29 @@ private View(Model model,
Label simHeadline = new Label(Res.get("reputation.sim.headline"));
simHeadline.getStyleClass().addAll("bisq-text-1");
amount = getInputField("reputation.sim.burnAmount");
int width = 380;
amount.setMinWidth(width);
amount.setMaxWidth(width);
score = getField(Res.get("reputation.sim.score"));
ageField = getInputField("reputation.sim.age");
simAgeSlider = new AgeSlider(0, ProofOfBurnService.MAX_AGE_BOOST_DAYS, 0);
VBox.setMargin(simAgeSlider.getView().getRoot(), new Insets(15, 0, 0, 0));
root.getChildren().addAll(simHeadline,
amount,
ageField,
simAgeSlider.getView().getRoot(),
score);
}

@Override
protected void onViewAttached() {
simAgeSlider.valueProperty().bindBidirectional(model.getAge());
ageField.textProperty().bindBidirectional(model.getAgeAsString());
amount.textProperty().bindBidirectional(model.getAmount());
score.textProperty().bind(model.getScore());
}

@Override
protected void onViewDetached() {
simAgeSlider.valueProperty().unbindBidirectional(model.getAge());
ageField.textProperty().unbindBidirectional(model.getAgeAsString());
amount.textProperty().unbindBidirectional(model.getAmount());
score.textProperty().unbind();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ protected void onViewAttached() {
closeButton.setOnAction(e -> controller.onClose());

root.setPrefWidth(OverlayModel.WIDTH);
root.setPrefHeight(OverlayModel.HEIGHT + 60);
root.setPrefHeight(OverlayModel.HEIGHT + 110);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,24 @@

import bisq.common.util.MathUtils;
import bisq.desktop.components.controls.MaterialTextField;
import bisq.desktop.main.content.reputation.build_reputation.components.AgeSlider;
import bisq.i18n.Res;
import bisq.presentation.parser.DoubleParser;
import bisq.user.reputation.ProofOfBurnService;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;

import java.util.concurrent.TimeUnit;

public class BurnScoreSimulation {

private final Controller controller;
Expand All @@ -48,46 +54,66 @@ public static class Controller implements bisq.desktop.common.view.Controller {
@Getter
private final View view;
private final Model model;
private Subscription scorePin;
private Subscription agePin, ageAsStringPin, amountPin;

private Controller() {
model = new Model();
view = new View(model, this);

model.getAmount().set("100");
model.getAge().set(0);
model.getAgeAsString().set("0");
}

@Override
public void onActivate() {
scorePin = EasyBind.subscribe(model.getAmount(), amount -> model.getScore().set(calculateSimScore(amount)));
agePin = EasyBind.subscribe(model.getAge(), age -> model.getAgeAsString().set(String.valueOf(age)));
ageAsStringPin = EasyBind.subscribe(model.getAgeAsString(), ageAsString -> {
try {
model.getAge().set(Integer.parseInt(ageAsString));
calculateSimScore();
} catch (Exception e) {
}
});
amountPin = EasyBind.subscribe(model.getAmount(), amount -> calculateSimScore());
}

@Override
public void onDeactivate() {
scorePin.unsubscribe();
agePin.unsubscribe();
ageAsStringPin.unsubscribe();
amountPin.unsubscribe();
}

private String calculateSimScore(String value) {
private void calculateSimScore() {
try {
// amountAsLong is the smallest unit of BSQ (100 = 1 BSQ)
long amountAsLong = Math.max(0, MathUtils.roundDoubleToLong(DoubleParser.parse(value) * 100));
long totalScore = ProofOfBurnService.doCalculateScore(amountAsLong);
return String.valueOf(totalScore);
long amountAsLong = Math.max(0, MathUtils.roundDoubleToLong(DoubleParser.parse(model.getAmount().get()) * 100));
long ageInDays = Math.max(0, model.getAge().get());
long age = TimeUnit.DAYS.toMillis(ageInDays);
long blockTime = System.currentTimeMillis() - age;
long totalScore = ProofOfBurnService.doCalculateScore(amountAsLong, blockTime);
String score = String.valueOf(totalScore);
model.getScore().set(score);
} catch (Exception e) {
return "";
log.error("Failed to calculate simScore", e);
}
}
}

@Getter
private static class Model implements bisq.desktop.common.view.Model {
private final StringProperty amount = new SimpleStringProperty();
private final IntegerProperty age = new SimpleIntegerProperty();
private final StringProperty ageAsString = new SimpleStringProperty();
private final StringProperty score = new SimpleStringProperty();
}

private static class View extends bisq.desktop.common.view.View<VBox, Model, Controller> {
private final MaterialTextField amount;
private final MaterialTextField score;
private final AgeSlider simAgeSlider;
private final MaterialTextField ageField;

private View(Model model,
Controller controller) {
Expand All @@ -97,19 +123,28 @@ private View(Model model,
simHeadline.getStyleClass().addAll("bisq-text-1");
amount = getInputField("reputation.sim.burnAmount");
score = getField(Res.get("reputation.sim.score"));
ageField = getInputField("reputation.sim.age");
simAgeSlider = new AgeSlider(0, ProofOfBurnService.MAX_AGE_BOOST_DAYS, 0);
VBox.setMargin(simAgeSlider.getView().getRoot(), new Insets(15, 0, 0, 0));
root.getChildren().addAll(simHeadline,
amount,
ageField,
simAgeSlider.getView().getRoot(),
score);
}

@Override
protected void onViewAttached() {
simAgeSlider.valueProperty().bindBidirectional(model.getAge());
ageField.textProperty().bindBidirectional(model.getAgeAsString());
amount.textProperty().bindBidirectional(model.getAmount());
score.textProperty().bind(model.getScore());
}

@Override
protected void onViewDetached() {
simAgeSlider.valueProperty().unbindBidirectional(model.getAge());
ageField.textProperty().unbindBidirectional(model.getAgeAsString());
amount.textProperty().unbindBidirectional(model.getAmount());
score.textProperty().unbind();
}
Expand All @@ -129,4 +164,4 @@ private MaterialTextField getInputField(String key) {
return field;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ public long calculateScore(AuthorizedAccountAgeData data) {
public static long doCalculateScore(long ageInDays) {
checkArgument(ageInDays >= 0);
long boundedAgeInDays = Math.min(MAX_DAYS_AGE_SCORE, ageInDays);
return MathUtils.roundDoubleToLong(boundedAgeInDays * WEIGHT);
double ageBoostFactor = getAgeBoostFactor(ageInDays);
return MathUtils.roundDoubleToLong(boundedAgeInDays * WEIGHT * ageBoostFactor);
}

public boolean requestAuthorization(String json) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import lombok.extern.slf4j.Slf4j;

import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static com.google.common.base.Preconditions.checkArgument;

Expand Down Expand Up @@ -75,11 +76,14 @@ protected ByteArray getUserProfileKey(UserProfile userProfile) {
@Override
public long calculateScore(AuthorizedBondedReputationData data) {
checkArgument(data.getLockTime() >= LOCK_TIME);
return doCalculateScore(data.getAmount());
return doCalculateScore(data.getAmount(), data.getBlockTime());
}

public static long doCalculateScore(long amount) {
public static long doCalculateScore(long amount, long blockTime) {
checkArgument(amount >= 0);
return MathUtils.roundDoubleToLong(amount / 100d * WEIGHT);
checkArgument(blockTime < System.currentTimeMillis() + TimeUnit.HOURS.toMillis(4),
"blockTime must not be more then 4 hours in future");
double ageBoostFactor = getAgeBoostFactor(blockTime);
return MathUtils.roundDoubleToLong(amount / 100d * WEIGHT * ageBoostFactor);
}
}
10 changes: 7 additions & 3 deletions user/src/main/java/bisq/user/reputation/ProofOfBurnService.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import lombok.extern.slf4j.Slf4j;

import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static com.google.common.base.Preconditions.checkArgument;

Expand Down Expand Up @@ -73,11 +74,14 @@ protected ByteArray getUserProfileKey(UserProfile userProfile) {

@Override
public long calculateScore(AuthorizedProofOfBurnData data) {
return doCalculateScore(data.getAmount());
return doCalculateScore(data.getAmount(), data.getBlockTime());
}

public static long doCalculateScore(long amount) {
public static long doCalculateScore(long amount, long blockTime) {
checkArgument(amount >= 0);
return MathUtils.roundDoubleToLong(amount / 100d * WEIGHT);
checkArgument(blockTime < System.currentTimeMillis() + TimeUnit.HOURS.toMillis(4),
"blockTime must not be more then 4 hours in future");
double ageBoostFactor = getAgeBoostFactor(blockTime);
return MathUtils.roundDoubleToLong(amount / 100d * WEIGHT * ageBoostFactor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ public static long doCalculateScore(long ageInDays) {
return 0;
}
long boundedAgeInDays = Math.min(MAX_DAYS_AGE_SCORE, ageInDays);
return MathUtils.roundDoubleToLong(boundedAgeInDays * WEIGHT);
double ageBoostFactor = getAgeBoostFactor(ageInDays);
return MathUtils.roundDoubleToLong(boundedAgeInDays * WEIGHT * ageBoostFactor);
}

private boolean doRequestAuthorization(String json) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
@Slf4j
public abstract class SourceReputationService<T extends AuthorizedDistributedData> implements Service, AuthorizedBondedRolesService.Listener {
protected static final long DAY_AS_MS = TimeUnit.DAYS.toMillis(1);
public static final int MAX_AGE_BOOST_DAYS = 365;
public static final double MAX_AGE_BOOST_PERIOD = TimeUnit.DAYS.toMillis(MAX_AGE_BOOST_DAYS);

public static long getAgeInDays(long date) {
return (System.currentTimeMillis() - date) / DAY_AS_MS;
Expand Down Expand Up @@ -152,4 +154,11 @@ public long getScore(String userProfileId) {
protected boolean isAuthorized(AuthorizedData authorizedData) {
return authorizedBondedRolesService.hasAuthorizedPubKey(authorizedData, BondedRoleType.ORACLE_NODE);
}

protected static double getAgeBoostFactor(long eventTime) {
checkArgument(eventTime >= 0);
long age = Math.max(0, System.currentTimeMillis() - eventTime);
double ageFactor = Math.min(1, age / MAX_AGE_BOOST_PERIOD);
return 1 + ageFactor;
}
}

0 comments on commit eaccf81

Please sign in to comment.