Commit 14b1bb03 authored by zeroleak's avatar zeroleak
Browse files

add pool.anonymity-set, remove...

add pool.anonymity-set, remove pool.anonymity-set-target/anonymity-set-min/anonymity-set-max/anonymity-set-adjust-timeout
parent 4c7ebedf
......@@ -71,19 +71,14 @@ SCode can expire for tx0s confirmed after a specified time.
### Pool: Mix limits
```
server.pools[x].anonymity-set-target = 10
server.pools[x].anonymity-set-min = 6
server.pools[x].anonymity-set-max = 20
server.pools[x].anonymity-set-adjust-timeout = 120
server.pools[x].anonymity-set = 5
server.pools[x].must-mix-min = 1
server.pools[x].liquidity-min = 1
```
Mix will start when *anonymity-set-target* (mustMix + liquidities) are registered.<br/>
If this target is not met after *anonymity-set-adjust-timeout*, it will be gradually decreased to *anonymity-set-min*.<br/>
Mix will start when *anonymity-set* (mustMix + liquidities) are registered.<br/>
At the beginning of the mix, only mustMix can register up, to *anonymity-set-max - liquidity-min*. Meanwhile, liquidities are placed on a waiting pool.<br/>
Liquidities are added as soon as *must-mix-min* is reached, up to *anonymity-set-max* inputs for the mix.
At the beginning of the mix, only mustMix can register up, to *anonymity-set - liquidity-min*. Meanwhile, liquidities are placed on a waiting pool.<br/>
Liquidities are added as soon as *must-mix-min* is reached, up to *anonymity-set* inputs for the mix.
### Exports
Each mix success/fail is appended to a CSV file:
......
......@@ -10,11 +10,7 @@ import com.samourai.whirlpool.server.services.CryptoService;
import com.samourai.whirlpool.server.utils.Utils;
import java.lang.invoke.MethodHandles;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;
......@@ -37,7 +33,6 @@ public class Mix {
private ScheduledFuture scheduleRegisterOutput;
private Pool pool;
private int targetAnonymitySet;
private MixStatus mixStatus;
private InputPool confirmingInputs;
......@@ -66,7 +61,6 @@ public class Mix {
this.scheduleRegisterOutput = null;
this.pool = pool;
this.targetAnonymitySet = pool.getTargetAnonymitySet();
this.mixStatus = MixStatus.CONFIRM_INPUT;
this.confirmingInputs = new InputPool();
......@@ -108,7 +102,7 @@ public class Mix {
}
public boolean isFull() {
return (getNbInputs() >= pool.getMaxAnonymitySet());
return (getNbInputs() >= pool.getAnonymitySet());
}
public String getMixId() {
......@@ -150,14 +144,6 @@ public class Mix {
return pool;
}
public int getTargetAnonymitySet() {
return targetAnonymitySet;
}
public void setTargetAnonymitySet(int targetAnonymitySet) {
this.targetAnonymitySet = targetAnonymitySet;
}
public MixStatus getMixStatus() {
return mixStatus;
}
......
......@@ -11,10 +11,7 @@ public class Pool {
private long minerFeeMax; // in satoshis
private int minMustMix;
private int minLiquidity;
private int targetAnonymitySet;
private int minAnonymitySet;
private int maxAnonymitySet;
private long timeoutAdjustAnonymitySet; // wait X seconds for decreasing anonymitySet
private int anonymitySet;
private Mix currentMix;
private InputPool mustMixQueue;
......@@ -29,10 +26,7 @@ public class Pool {
long minerFeeMax,
int minMustMix,
int minLiquidity,
int targetAnonymitySet,
int minAnonymitySet,
int maxAnonymitySet,
long timeoutAdjustAnonymitySet) {
int anonymitySet) {
this.poolId = poolId;
this.denomination = denomination;
this.poolFee = poolFee;
......@@ -41,10 +35,7 @@ public class Pool {
this.minerFeeMax = minerFeeMax;
this.minMustMix = minMustMix;
this.minLiquidity = minLiquidity;
this.targetAnonymitySet = targetAnonymitySet;
this.minAnonymitySet = minAnonymitySet;
this.maxAnonymitySet = maxAnonymitySet;
this.timeoutAdjustAnonymitySet = timeoutAdjustAnonymitySet;
this.anonymitySet = anonymitySet;
this.mustMixQueue = new InputPool();
this.liquidityQueue = new InputPool();
}
......@@ -114,20 +105,8 @@ public class Pool {
return minLiquidity;
}
public int getTargetAnonymitySet() {
return targetAnonymitySet;
}
public int getMinAnonymitySet() {
return minAnonymitySet;
}
public int getMaxAnonymitySet() {
return maxAnonymitySet;
}
public long getTimeoutAdjustAnonymitySet() {
return timeoutAdjustAnonymitySet;
public int getAnonymitySet() {
return anonymitySet;
}
public Mix getCurrentMix() {
......
......@@ -300,10 +300,7 @@ public class WhirlpoolServerConfig extends ServerConfig {
private long minerFeeMax;
private int mustMixMin;
private int liquidityMin;
private int anonymitySetTarget;
private int anonymitySetMin;
private int anonymitySetMax;
private long anonymitySetAdjustTimeout;
private int anonymitySet;
public String getId() {
return id;
......@@ -377,36 +374,12 @@ public class WhirlpoolServerConfig extends ServerConfig {
this.liquidityMin = liquidityMin;
}
public int getAnonymitySetTarget() {
return anonymitySetTarget;
public int getAnonymitySet() {
return anonymitySet;
}
public void setAnonymitySetTarget(int anonymitySetTarget) {
this.anonymitySetTarget = anonymitySetTarget;
}
public int getAnonymitySetMin() {
return anonymitySetMin;
}
public void setAnonymitySetMin(int anonymitySetMin) {
this.anonymitySetMin = anonymitySetMin;
}
public int getAnonymitySetMax() {
return anonymitySetMax;
}
public void setAnonymitySetMax(int anonymitySetMax) {
this.anonymitySetMax = anonymitySetMax;
}
public long getAnonymitySetAdjustTimeout() {
return anonymitySetAdjustTimeout;
}
public void setAnonymitySetAdjustTimeout(long anonymitySetAdjustTimeout) {
this.anonymitySetAdjustTimeout = anonymitySetAdjustTimeout;
public void setAnonymitySet(int anonymitySet) {
this.anonymitySet = anonymitySet;
}
}
......@@ -633,12 +606,7 @@ public class WhirlpoolServerConfig extends ServerConfig {
+ ", feeAccept="
+ (poolConfig.feeAccept != null ? poolConfig.feeAccept : null)
+ ", anonymitySet="
+ poolConfig.anonymitySetTarget
+ "["
+ poolConfig.anonymitySetMin
+ "-"
+ poolConfig.anonymitySetMax
+ "]";
+ poolConfig.anonymitySet;
poolInfo +=
", mustMixMin="
+ poolConfig.getMustMixMin()
......
......@@ -62,10 +62,10 @@ public class PoolsController extends AbstractRestController {
pool.computeMustMixBalanceMin(),
pool.computeMustMixBalanceCap(),
pool.computeMustMixBalanceMax(),
pool.getMinAnonymitySet(),
pool.getAnonymitySet(),
pool.getMinMustMix(),
nbRegistered,
currentMix.getTargetAnonymitySet(),
pool.getAnonymitySet(),
currentMix.getMixStatus(),
currentMix.getElapsedTime(),
nbConfirmed);
......
......@@ -60,9 +60,7 @@ public class StatusWebController {
poolAttributes.put("feeValue", pool.getPoolFee().getFeeValue());
poolAttributes.put("feeAccept", pool.getPoolFee().getFeeAccept());
poolAttributes.put("mixStatus", mix.getMixStatus());
poolAttributes.put("targetAnonymitySet", mix.getTargetAnonymitySet());
poolAttributes.put("maxAnonymitySet", pool.getMaxAnonymitySet());
poolAttributes.put("minAnonymitySet", pool.getMinAnonymitySet());
poolAttributes.put("anonymitySet", pool.getAnonymitySet());
poolAttributes.put("minMustMix", pool.getMinMustMix());
poolAttributes.put("minLiquidity", pool.getMinLiquidity());
poolAttributes.put("minerFeeMin", pool.getMinerFeeMin());
......
......@@ -111,13 +111,6 @@ public class MixLimitsService {
Long timeToWait = null;
switch (mix.getMixStatus()) {
case CONFIRM_INPUT:
if (mix.getTargetAnonymitySet() > mix.getPool().getMinAnonymitySet()) {
// timeout before next targetAnonymitySet adjustment
timeToWait = mix.getPool().getTimeoutAdjustAnonymitySet() * 1000 - elapsedTime;
}
break;
case REGISTER_OUTPUT:
timeToWait =
whirlpoolServerConfig.getRegisterOutput().getTimeout() * 1000 - elapsedTime;
......@@ -150,11 +143,6 @@ public class MixLimitsService {
log.debug("limitsWatcher.onTimeout");
}
switch (mix.getMixStatus()) {
case CONFIRM_INPUT:
// adjust targetAnonymitySet
adjustTargetAnonymitySet(mix, timeoutWatcher);
break;
case REGISTER_OUTPUT:
mixService.onTimeoutRegisterOutput(mix);
break;
......@@ -227,34 +215,6 @@ public class MixLimitsService {
// CONFIRM_INPUT
private void adjustTargetAnonymitySet(Mix mix, TimeoutWatcher timeoutWatcher) {
// no input registered yet => nothing to do
if (mix.getNbInputs() == 0) {
return;
}
// anonymitySet already at minimum
if (mix.getPool().getMinAnonymitySet() >= mix.getTargetAnonymitySet()) {
return;
}
// adjust mustMix
int nextTargetAnonymitySet = mix.getTargetAnonymitySet() - 1;
log.info(
" • must-mix-adjust-timeout over, adjusting targetAnonymitySet: " + nextTargetAnonymitySet);
mix.setTargetAnonymitySet(nextTargetAnonymitySet);
timeoutWatcher.resetTimeout();
// is mix ready now?
if (mixService.isRegisterInputReady(mix)) {
// add max possible liquidities (when maxAnonSet>currentAnonSet)
addLiquidities(mix);
// notify mixService - which doesn't know targetAnonymitySet was adjusted
mixService.checkConfirmInputReady(mix);
}
}
public synchronized void onInputConfirmed(Mix mix) {
// first mustMix registered => instanciate limitsWatcher & liquidityWatcher
if (mix.getNbInputs() == 1) {
......@@ -275,7 +235,7 @@ public class MixLimitsService {
return;
}
int liquiditiesToAdd = mix.getPool().getMaxAnonymitySet() - mix.getNbInputs();
int liquiditiesToAdd = mix.getPool().getAnonymitySet() - mix.getNbInputs();
if (liquiditiesToAdd > 0) {
// add queued liquidities if any
liquiditiesToAdd++; // invite one more liquidity to prevent more waiting if one disconnects
......@@ -283,8 +243,8 @@ public class MixLimitsService {
} else {
if (log.isDebugEnabled()) {
log.debug(
"No liquidity to add: maxAnonymitySet="
+ mix.getPool().getMaxAnonymitySet()
"No liquidity to add: anonymitySet="
+ mix.getPool().getAnonymitySet()
+ ", nbInputs="
+ mix.getNbInputs());
}
......
......@@ -116,7 +116,7 @@ public class MixService {
}
} else {
// mustMix: verify minLiquidity
int liquiditySlotsAvailable = pool.getMaxAnonymitySet() - (mix.getNbInputsMustMix() + 1);
int liquiditySlotsAvailable = pool.getAnonymitySet() - (mix.getNbInputsMustMix() + 1);
if (liquiditySlotsAvailable < pool.getMinLiquidity()) {
throw new QueueInputException(
"Current mix is full for mustMix", registeredInput, pool.getPoolId());
......@@ -233,15 +233,15 @@ public class MixService {
if (allowGracePeriod
&& GRACE_TIME_CONFIRMING_INPUTS > 0
&& mix.hasPendingConfirmingInputs()
&& mix.getNbInputs() < mix.getPool().getMaxAnonymitySet()) {
&& mix.getNbInputs() < mix.getPool().getAnonymitySet()) {
if (log.isDebugEnabled()) {
log.debug(
"Ready to go REGISTER_OUTPUT - waiting for last pending confirmations: pendingConfirmingInputs="
+ mix.getNbConfirmingInputs()
+ ", nbInputs="
+ mix.getNbInputs()
+ ", maxAnonymitySet="
+ mix.getPool().getMaxAnonymitySet());
+ ", anonymitySet="
+ mix.getPool().getAnonymitySet());
}
// allow grace period for pending inputs confirmations...
......@@ -293,7 +293,7 @@ public class MixService {
if (!mix.hasMinLiquidityMixReached()) {
return false;
}
if (mix.getNbInputs() < mix.getTargetAnonymitySet()) {
if (mix.getNbInputs() < mix.getPool().getAnonymitySet()) {
return false;
}
// check for inputs spent in the meantime
......@@ -341,7 +341,7 @@ public class MixService {
+ " liquidity, "
+ mix.getNbInputs()
+ "/"
+ mix.getTargetAnonymitySet()
+ mix.getPool().getAnonymitySet()
+ " anonymitySet (pool: "
+ liquiditiesQueued
+ " liquidities + "
......
......@@ -66,10 +66,7 @@ public class PoolService {
long minerFeeMax = poolConfig.getMinerFeeMax();
int minMustMix = poolConfig.getMustMixMin();
int minLiquidity = poolConfig.getLiquidityMin();
int targetAnonymitySet = poolConfig.getAnonymitySetTarget();
int minAnonymitySet = poolConfig.getAnonymitySetMin();
int maxAnonymitySet = poolConfig.getAnonymitySetMax();
long mustMixAdjustTimeout = poolConfig.getAnonymitySetAdjustTimeout();
int anonymitySet = poolConfig.getAnonymitySet();
Assert.notNull(poolId, "Pool configuration: poolId must not be NULL");
Assert.isTrue(!pools.containsKey(poolId), "Pool configuration: poolId must not be duplicate");
......@@ -84,10 +81,7 @@ public class PoolService {
minerFeeMax,
minMustMix,
minLiquidity,
targetAnonymitySet,
minAnonymitySet,
maxAnonymitySet,
mustMixAdjustTimeout);
anonymitySet);
pools.put(poolId, pool);
}
}
......
......@@ -52,10 +52,7 @@ server.pools[0].miner-fee-cap = 9500
server.pools[0].miner-fee-max = 10000
server.pools[0].must-mix-min = 1
server.pools[0].liquidity-min = 1
server.pools[0].anonymity-set-target = 2
server.pools[0].anonymity-set-min = 1
server.pools[0].anonymity-set-max = 20
server.pools[0].anonymity-set-adjust-timeout = 120
server.pools[0].anonymity-set = 1
# pool 1
server.pools[1].id = 0.1btc
......@@ -66,10 +63,7 @@ server.pools[1].miner-fee-cap = 9500
server.pools[1].miner-fee-max = 10000
server.pools[1].must-mix-min = 1
server.pools[1].liquidity-min = 1
server.pools[1].anonymity-set-target = 2
server.pools[1].anonymity-set-min = 1
server.pools[1].anonymity-set-max = 20
server.pools[1].anonymity-set-adjust-timeout = 120
server.pools[1].anonymity-set = 1
# pool 2
server.pools[2].id = 0.01btc
......@@ -80,10 +74,7 @@ server.pools[2].miner-fee-cap = 9500
server.pools[2].miner-fee-max = 10000
server.pools[2].must-mix-min = 1
server.pools[2].liquidity-min = 1
server.pools[2].anonymity-set-target = 2
server.pools[2].anonymity-set-min = 1
server.pools[2].anonymity-set-max = 20
server.pools[2].anonymity-set-adjust-timeout = 120
server.pools[2].anonymity-set = 1
management.endpoints.web.exposure.exclude=*
management.endpoints.jmx.exposure.exclude=*
......
......@@ -44,7 +44,7 @@
</div>
</td>
<td>
<strong><span th:text="${pool.nbInputs}"/> / <span th:text="${pool.targetAnonymitySet}"/> confirmed</strong><br/>
<strong><span th:text="${pool.nbInputs}"/> / <span th:text="${pool.anonymitySet}"/> confirmed</strong><br/>
<span th:text="${pool.nbInputsMustMix}" style="font-weight:bold"/> / <span th:text="${pool.minMustMix}"/> mustMix<br/>
<span th:text="${pool.nbInputsLiquidities}" style="font-weight:bold"/> / <span th:text="${pool.minLiquidity}"/> liquidities + <span th:text="${pool.liquiditiesQueued}" style="font-weight:bold"/> queued
</td>
......@@ -52,7 +52,6 @@
<td>
Pool fee: <span th:text="${@templateUtil.satoshisToBtc(pool.feeValue)}"/><br/>
Miner fee: <span th:text="${pool.minerFeeMin}" title="minerFeeMin"/>-<span th:text="${pool.minerFeeMax}" title="minerFeeMax"/> (cap <span th:text="${pool.minerFeeCap}" title="minerFeeMaxCap"/>)<br/>
AnonymitySet: <span th:text="${pool.minAnonymitySet}"/>-<span th:text="${pool.maxAnonymitySet}"/>
</td>
</tr>
<tr>
......
......@@ -139,11 +139,7 @@ public abstract class AbstractIntegrationTest {
long minerFeeMax,
int mustMixMin,
int liquidityMin,
int anonymitySetTarget,
int anonymitySetMin,
int anonymitySetMax,
long anonymitySetAdjustTimeout,
long liquidityTimeout)
int anonymitySet)
throws IllegalInputException {
// create new pool
WhirlpoolServerConfig.PoolConfig poolConfig = new WhirlpoolServerConfig.PoolConfig();
......@@ -155,10 +151,7 @@ public abstract class AbstractIntegrationTest {
poolConfig.setMinerFeeMax(minerFeeMax);
poolConfig.setMustMixMin(mustMixMin);
poolConfig.setLiquidityMin(liquidityMin);
poolConfig.setAnonymitySetTarget(anonymitySetTarget);
poolConfig.setAnonymitySetMin(anonymitySetMin);
poolConfig.setAnonymitySetMax(anonymitySetMax);
poolConfig.setAnonymitySetAdjustTimeout(anonymitySetAdjustTimeout);
poolConfig.setAnonymitySet(anonymitySet);
// run new mix for the pool
return __nextMix(poolConfig);
......@@ -177,10 +170,7 @@ public abstract class AbstractIntegrationTest {
poolConfig.setMinerFeeMax(copyPool.getMinerFeeMax());
poolConfig.setMustMixMin(mustMixMin);
poolConfig.setLiquidityMin(liquidityMin);
poolConfig.setAnonymitySetTarget(anonymitySet);
poolConfig.setAnonymitySetMin(anonymitySet);
poolConfig.setAnonymitySetMax(anonymitySet);
poolConfig.setAnonymitySetAdjustTimeout(copyPool.getTimeoutAdjustAnonymitySet());
poolConfig.setAnonymitySet(anonymitySet);
// run new mix for the pool
return __nextMix(poolConfig);
......
......@@ -35,11 +35,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
long minerFeeMax = 10000;
int mustMixMin = NB_CLIENTS;
int liquidityMin = 0;
int anonymitySetTarget = NB_CLIENTS;
int anonymitySetMin = NB_CLIENTS;
int anonymitySetMax = NB_CLIENTS;
long anonymitySetAdjustTimeout = 10 * 60; // 10 minutes
long liquidityTimeout = 60;
int anonymitySet = NB_CLIENTS;
Mix mix =
__nextMix(
denomination,
......@@ -49,11 +45,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
minerFeeMax,
mustMixMin,
liquidityMin,
anonymitySetTarget,
anonymitySetMin,
anonymitySetMax,
anonymitySetAdjustTimeout,
liquidityTimeout);
anonymitySet);
AssertMultiClientManager multiClientManager = multiClientManager(NB_CLIENTS, mix);
......@@ -88,11 +80,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
long minerFeeMax = 10000;
int mustMixMin = NB_CLIENTS;
int liquidityMin = 0;
int anonymitySetTarget = NB_CLIENTS;
int anonymitySetMin = NB_CLIENTS;
int anonymitySetMax = NB_CLIENTS;
long anonymitySetAdjustTimeout = 10 * 60; // 10 minutes
long liquidityTimeout = 60;
int anonymitySet = NB_CLIENTS;
Mix mix =
__nextMix(
denomination,
......@@ -102,11 +90,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
minerFeeMax,
mustMixMin,
liquidityMin,
anonymitySetTarget,
anonymitySetMin,
anonymitySetMax,
anonymitySetAdjustTimeout,
liquidityTimeout);
anonymitySet);
AssertMultiClientManager multiClientManager = multiClientManager(NB_CLIENTS, mix);
long premixBalanceMin = mix.getPool().computePremixBalanceMin(false);
......@@ -149,11 +133,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
long minerFeeMax = 10000;
int mustMixMin = 3;
int liquidityMin = 0;
int anonymitySetTarget = NB_CLIENTS;
int anonymitySetMin = NB_CLIENTS;
int anonymitySetMax = NB_CLIENTS;
long anonymitySetAdjustTimeout = 10 * 60; // 10 minutes
long liquidityTimeout = 1;
int anonymitySet = NB_CLIENTS;
Mix mix =
__nextMix(
denomination,
......@@ -163,11 +143,7 @@ public class Whirlpool10ClientsIntegrationTest extends AbstractIntegrationTest {
minerFeeMax,
mustMixMin,
liquidityMin,
anonymitySetTarget,
anonymitySetMin,
anonymitySetMax,
anonymitySetAdjustTimeout,
liquidityTimeout);
anonymitySet);
AssertMultiClientManager multiClientManager = multiClientManager(NB_CLIENTS, mix);
......
......@@ -383,11 +383,7 @@ public class Whirlpool5WalletsIntegrationTest extends WhirlpoolSimpleIntegration
long minerFeeMax = mixFee * 10;
int mustMixMin = NB_CLIENTS;
int liquidityMin = 0;
int anonymitySetTarget = NB_CLIENTS;
int anonymitySetMin = NB_CLIENTS;
int anonymitySetMax = NB_CLIENTS;
long anonymitySetAdjustTimeout = 10 * 60; // 10 minutes
long liquidityTimeout = 60;
int anonymitySet = NB_CLIENTS;
Mix mix =
__nextMix(
denomination,
......@@ -397,11 +393,7 @@ public class Whirlpool5WalletsIntegrationTest extends WhirlpoolSimpleIntegration
minerFeeMax,
mustMixMin,
liquidityMin,
anonymitySetTarget,
anonymitySetMin,
anonymitySetMax,
anonymitySetAdjustTimeout,
liquidityTimeout);
anonymitySet);
AssertMultiClientManager multiClientManager = multiClientManager(NB_CLIENTS, mix);
......
......@@ -36,11 +36,7 @@ public class WhirlpoolMultiMixIntegrationTest extends AbstractIntegrationTest {
long minerFeeMax = 10000;
int mustMixMin = 1;
int liquidityMin = 0;
int anonymitySetTarget = NB_CLIENTS_FIRST_MIX;
int anonymitySetMin = 1;
int anonymitySetMax = NB_CLIENTS_FIRST_MIX;
long anonymitySetAdjustTimeout = 10 * 60; // 10 minutes
long liquidityTimeout = 60;
int anonymitySet = NB_CLIENTS_FIRST_MIX;
Mix mix =
__nextMix(
denomination,
......@@ -50,11 +46,7 @@ public class WhirlpoolMultiMixIntegrationTest extends AbstractIntegrationTest {
minerFeeMax,
mustMixMin,